-- test
Utils = {}
bot = require("robot")
math = require("math")
com = require("computer")
sides = require("sides")
thread = require("thread")
Ser = require('serialization')
Component = require('component')
event = require('event')
selectLocked = 0
Utils.getLock = function(lock_id, callback, ...)
    if (lock_id == nil) then
        lock_id = 1
    end
    while (selectLocked ~= lock_id and selectLocked ~= 0) do
        os.sleep(1)
    end
    if (selectLocked == 0) then
        selectLocked = lock_id
    end
    if (callback ~= nil) then
        callback(...)
    end
    selectLocked = 0
end
Utils.select = function(slot_id, lock_id, callback, willReturn)
    if (slot_id == nil) then
        return bot.select()
    end
    if (lock_id == nil) then
        lock_id = 1
    end

    if (willReturn == nil) then
        willReturn = false
    end

    while (selectLocked ~= lock_id and selectLocked ~= 0) do
        os.sleep(1)
    end
    if (selectLocked == 0) then
        selectLocked = lock_id
    end
    local lastSlotId = bot.select()
    local selectResult = bot.select(slot_id)
    if (callback ~= nil) then
        callback()
    end
    if (willReturn) then
        bot.select(lastSlotId)
    end
    selectLocked = 0
    return selectResult
end

Utils.mySleep = function()
    os.sleep(1)
end
Utils.xor = function(a, b)
    if (a and b or not a and not b) then
        return true
    else
        return false
    end
end
Utils.turn = function(a)
    --[[
if a==0 this function will do nothing
if a>0 this function will let the robot turnRight 'a' times
if a<0 this funciton will let the robot turnLeft 'a' times
]]
    if (a ~= 0) then
        for i = 1, math.abs(a) do
            if (a < 0) then
                Utils.turnLeft()
            else
                Utils.turnRight()
            end
            Utils.mySleep()
        end
    end
end
Utils.detectLeft = function()
    bot.turnLeft()
    res = bot.detect()
    bot.turnRight()
    return res
end
Utils.detectRight = function()
    bot.turnRight()
    res = bot.detect()
    bot.turnLeft()
    return res
end
Utils.totalCount = function()
    local sum = 0
    for i = 1, bot.inventorySize() do
        sum = sum + bot.count(i)
    end
    return sum
end

Utils.up = function(n, force)
    if (n == nil) then
        while (bot.up() == nil) do
            if (force) then
                Utils.swingUp(false)
            end

            os.sleep(3)
        end
        Utils.mySleep()
    else
        for i = 1, n do
            while (bot.up() == nil) do
                if (force) then
                    Utils.swingUp(false)
                end
                os.sleep(3)
            end
            Utils.mySleep()
        end
    end
end

Utils.down = function(n, force)
    if (n == nil) then
        while (bot.down() == nil) do
            if (force) then
                Utils.swingDown(false)
            end
            os.sleep(3)
        end

        Utils.mySleep()
    else
        for i = 1, n do
            while (bot.down() == nil) do
                if (force) then
                    Utils.swingDown(false)
                end
                os.sleep(3)
            end
            Utils.mySleep()
        end
    end
end
Utils.forward = function(n, force)
    -- Utils.checkEnergy()

    if (n == nil) then
        while (bot.forward() == nil) do
            if (force) then
                Utils.swing(false)
            end
            os.sleep(3)
        end

        Utils.mySleep()
    else
        for i = 1, n do
            while (bot.forward() == nil) do
                if (force) then
                    Utils.swing(false)
                end
                os.sleep(3)
            end
            Utils.mySleep()
        end
    end
end

Utils.back = function(n)
    if (n == nil) then
        while (bot.back() == nil) do
            os.sleep(3)
        end
    else
        for i = 1, n do
            while (bot.back() == nil) do
                os.sleep(3)
            end

            Utils.mySleep()
        end
    end
end
-- Utils.checkEnergy = function(fuelName, number, energyThreshold)

-- 	if (energyThreshold == nil) then
-- 		energyThreshold = 5000
-- 	end
-- 	if (fuelName == nil) then
-- 		fuelName = 'forestry:charcoal'
-- 	end
-- 	if (number == nil) then
-- 		number = 1
-- 	end

-- 	if (com.energy() >= energyThreshold) then
-- 		return "enough energy"
-- 	end
-- 	ic = require('component').inventory_controller
-- 	g = require('component').generator
-- 	if (g == nil) then --????????????????????????
-- 		return "no generator upgrade"
-- 	end
-- 	if (g.count() ~= 0) then
-- 		return "is still burning"
-- 	end
-- 	local formerSlot = Utils.select() --???????????
-- 	local size = bot.inventorySize()
-- 	if (ic == nil) then --?????????????????????????????????????????????
-- 		--????????????
-- 		--???????????? number

-- 		for i = 1, size do
-- 			local slotCount = bot.count(i) --?????????????????
-- 			if (slotCount < number) then --???????????????????????
-- 				--????????????????????
-- 				Utils.select(i)
-- 				local res, message = g.insert()
-- 				if (res == false) then --?????????
-- 					if (message == 'selected slot does not contain fuel') then --????
-- 					elseif (message == 'different fuel type already queued') then --????
-- 					elseif (message == 'queue is full') then
-- 						break --??????????
-- 					end
-- 				else
-- 					--?????????
-- 					--???????????????????????????
-- 					--????????????64??,?????????????????
-- 					--??????????????64???????????????????????????????????????????
-- 					if (g.count() == 64) then
-- 						break
-- 					else
-- 						number = number - slotCount --???????????????????
-- 						--???????????
-- 					end
-- 				end

-- 			else --??????????????????????
-- 				--?????????????????????
-- 				Utils.select(i)
-- 				local res, message = g.insert(number)
-- 				if (res == false) then --?????????
-- 					if (message == 'selected slot does not contain fuel') then --????
-- 					elseif (message == 'different fuel type already queued') then --????
-- 					elseif (message == 'queue is full') then
-- 						break --??????????
-- 					end
-- 				else
-- 					--?????????
-- 					--?????????????
-- 					--???????number????????
-- 					--??????number???????????????????
-- 					break
-- 				end
-- 			end
-- 		end
-- 	else --?????????????????
-- 		--??????
-- 		for i = 1, size do
-- 			local stack = ic.getStackInInternalSlot(i)

-- 			if (stack ~= nil and ic.getStackInInternalSlot(i).name == fuelName) then
-- 				local slotCount = bot.count(i) --?????????????????
-- 				if (slotCount < number) then --???????????????????????

-- 					--????????????????????
-- 					Utils.select(i)
-- 					local res, message = g.insert()
-- 					if (res == false) then --?????????
-- 						if (message == 'selected slot does not contain fuel') then --????
-- 							print('are you sure the fuelName is actually a fuelName?')
-- 							break
-- 						elseif (message == 'different fuel type already queued') then --????
-- 							print(message)
-- 							break
-- 						elseif (message == 'queue is full') then
-- 							break --??????????
-- 						end
-- 					else
-- 						--?????????
-- 						--???????????????????????????
-- 						--????????????64??,?????????????????
-- 						--??????????????64???????????????????????????????????????????
-- 						if (g.count() == 64) then
-- 							break
-- 						else
-- 							number = number - slotCount --???????????????????
-- 							--???????????
-- 						end
-- 					end

-- 				else --??????????????????????
-- 					--?????????????????????
-- 					Utils.select(i)
-- 					local res, message = g.insert(number)
-- 					if (res == false) then --?????????
-- 						if (message == 'selected slot does not contain fuel') then --????
-- 							print('are you sure the fuelName is actually a fuelName?')
-- 							break
-- 						elseif (message == 'different fuel type already queued') then --????
-- 							print(message)
-- 							break
-- 						elseif (message == 'queue is full') then
-- 							break --??????????
-- 						end
-- 					else
-- 						--?????????
-- 						--?????????????
-- 						--???????number????????
-- 						--??????number???????????????????
-- 						break
-- 					end
-- 				end

-- 			end

-- 		end

-- 	end

-- 	Utils.select(formerSlot) --???????????
-- end
Utils.turnAround = function()
    bot.turnLeft()
    bot.turnLeft()
end
Utils.upForward = function(a, b)
    Utils.up(a)
    Utils.forward(b)
end
Utils.getFirstPossibleSlot = function()
    for i = 1, bot.inventorySize() do
        if (bot.count(i) ~= 0) then
            return i
        end
    end
end

Utils.placeAutoSelect = function()
    if (bot.count() == 0) then
        local firstPos = Utils.getFirstPossibleSlot()
        Utils.select(firstPos, 1, bot.place)
    else
        bot.place()
    end
end
Utils.placeDownAutoSelect = function()
    if (bot.count() == 0) then
        local firstPos = Utils.getFirstPossibleSlot()
        Utils.select(firstPos, 1, bot.placeDown)
    else
        bot.placeDown()
    end
end
Utils.placeUpAutoSelect = function()
    if (bot.count() == 0) then
        local firstPos = Utils.getFirstPossibleSlot()
        Utils.select(firstPos, 1, bot.placeUp)
    else
        bot.placeUp()
    end
end
Utils.placeColumn = function(height)
    max = 0
    local i = 1
    Utils.placeAutoSelect()
    while (i < height) do
        if (bot.detectUp()) then
            break
        end
        Utils.up(1)
        i = i + 1
        Utils.placeAutoSelect()
    end
    Utils.down(i - 1)
end
function test()
    bot.forward()
end

Utils.turnLeft = function()
    bot.turnLeft()
end
Utils.turnRight = function()
    bot.turnRight()
end
Utils.moveLeft = function(...)
    args = { ... }
    if (#args == 0) then
        Utils.turnLeft()
        Utils.forward()
        Utils.turnRight()
    elseif (#args == 1) then
        Utils.turnLeft()
        Utils.forward(args[1])
        Utils.turnRight()
    else
        Utils.turnLeft()
        Utils.forward(args[1], args[2])
        Utils.turnRight()
    end
end
Utils.moveRight = function(...)
    args = { ... }
    if (#args == 0) then
        Utils.turnRight()
        Utils.forward()
        Utils.turnLeft()
    elseif (#args == 1) then
        Utils.turnRight()
        Utils.forward(args[1])
        Utils.turnLeft()
    else
        Utils.turnRight()
        Utils.forward(args[1], args[2])
        Utils.turnLeft()
    end
end
Utils.placeWallWithNoReturn = function(width, height, isLeft)
    if (width <= 0 or height <= 0) then
        return "illegal arguments"
    elseif (Utils.totalCount() < width * height) then
        return "not enough blocks"
    else
        for i = 1, width do
            Utils.placeColumn(height)
            if (isLeft) then
                Utils.moveLeft()
            else
                Utils.moveRight()
            end
        end
        return "OK"
    end
end
Utils.placeWallToRightWithNoReturn = function(width, height)
    return Utils.placeWallWithNoReturn(width, height, false)
end

Utils.placeWallToLeftWithNoReturn = function(width, height)
    return Utils.placeWallWithNoReturn(width, height, true)
end

Utils.placeHorizonalBar = function(length, isAbove, ret)
    --[[
try to place a horizonalBar Above/below the robot with return/ no return
default: place a horizonalBar below the robot with return
]]
    if (isAbove == nil) then
        isAbove = false
    end
    if (ret == nil) then
        ret = true
    end
    if (isAbove) then
        Utils.placeUpAutoSelect()
    else
        Utils.placeDownAutoSelect()
    end
    local i = 1
    while (i < length) do
        if (not bot.detect()) then
            bot.forward()
            i = i + 1
            if (isAbove) then
                Utils.placeUpAutoSelect()
            else
                Utils.placeDownAutoSelect()
            end
        else
            break
        end
    end
    if (ret) then
        Utils.back(i - 1)
    end
end
Utils.placeFloor = function(length, width, isRight, isAhead, ret)
    --[[
this method calls the robot to place Floor
using any possible blocks in robot's backpack
length is for left-right direction;
width is for forward-back direction.
if 3rd and 4th args are not inputted,
they will be true .
utils?????????????
do then
ret default set true
]]
    if (ret == nil) then
        ret = true
    end
    if (length <= 0 or width <= 0) then
        return "illegal arguments"
    elseif (Utils.totalCount() < length * width) then
        return "not enough blocks"
    end
    if (isAhead == nil) then
        isAhead = true
    end
    if (isRight == nil) then
        isRight = true
    end
    if (not isAhead) then
        Utils.turnAround()
    end
    R = Utils.xor(isAhead, isRight)

    local i = 1
    Utils.placeHorizonalBar(width)

    while (i < length) do
        if (R) then
            res = Utils.detectRight()
        else
            res = Utils.detectLeft()
        end
        if (not res) then
            if (R) then
                Utils.moveRight()
            else
                Utils.moveLeft()
            end
            i = i + 1
            Utils.placeHorizonalBar(width)
        else
            break
        end
    end
    if (ret) then
        -- if you want to come back to the original place
        if (Utils.xor(isRight, isAhead)) then
            Utils.moveLeft(i - 1)
        else
            Utils.moveRight(i - 1)
        end
        if (not isAhead) then
            Utils.turnAround()
        end
    end

    return "OK"
end
placeHollowRectangle = function(length, width, isRight, isAhead, isAbove)
    --[[
try to place a hollow rectangle above or below the robot
default: place at right,ahead and above.
]]
    if (isRight == nil) then
        -- default setting
        isRight = true
    end
    if (isAhead == nil) then
        -- default setting
        isAhead = true
    end
    if (isAbove == nil) then
        isAbove = false
    end

    local around = false
    local turntable = {}
    if (isRight and isAhead) then
        around = false
        turntable = { 1, 1, 1, 1 }
    elseif (not isRight and isAhead) then
        around = false
        turntable = { -1, -1, -1, -1 }
    elseif (isRight and not isAhead) then
        around = true
        turntable = { -1, -1, -1, -1 }
    elseif (not isRight and not isAhead) then
        around = true
        turntable = { 1, 1, 1, 1 }
    end
    if (around) then
        Utils.turnAround()
    end
    Utils.placeHorizonalBar(width, isAbove, false) -- calls the function to place a horizonal bar
    Utils.turn(turntable[1])
    Utils.placeHorizonalBar(length, isAbove, false)
    Utils.turn(turntable[2])
    Utils.placeHorizonalBar(width, isAbove, false)
    Utils.turn(turntable[3])
    Utils.placeHorizonalBar(length, isAbove, false)
    Utils.turn(turntable[4])
    if (around) then
        Utils.turnAround()
    end
end
Utils.placeHollowRectangleBelow = function(length, width, isRight, isAhead)
    placeHollowRectangle(length, width, isRight, isAhead, false)
end
Utils.placeHollowRectangleAbove = function(length, width, isRight, isAhead)
    placeHollowRectangle(length, width, isRight, isAhead, true)
end

Utils.buildHollowCuboid = function(length, width, height, isRight, isAhead)
    if (height <= 0) then
        return "illegal arguments height:at least bigger than 0"
    end
    Utils.placeFloor(length, width, isRight, isAhead)
    for i = 1, height - 1 do
        Utils.up(1)
        Utils.placeHollowRectangleBelow(length, width, isRight, isAhead)
    end
    Utils.placeFloor(length, width, isRight, isAhead)
end
Utils.buildMuitiLayerHC = function(length, width, height, layersNum, isRight, isAhead)
    if (layersNum == nil) then
        layersNum = 1
    end
    for i = 1, layersNum do
        Utils.buildHollowCuboid(length, width, height, isRight, isAhead)
    end
end
Utils.buildCuboid = function(length, width, height, isRight, isAhead)
    if (height <= 0) then
        return "illegal arguments height:at least bigger than 0"
    end
    Utils.placeFloor(length, width, isRight, isAhead, true)
    for i = 1, height - 1 do
        Utils.up()
        Utils.placeFloor(length, width, isRight, isAhead, true)
    end
end
Utils.getTotalNumOf = function(givenName, label)
    local ic = require("component").inventory_controller
    local sum = 0
    size = bot.inventorySize()
    for i = 1, size do
        local item = ic.getStackInInternalSlot(i)
        if (item ~= nil) then
            local itemName = item.name
            if (itemName == givenName) then
                if label ~= nil then
                    if (item.label == label) then
                        sum = sum + bot.count(i)
                    end
                else
                    sum = sum + bot.count(i)
                end
            end
        end
    end
    return sum
end
-- Utils.selectByName = function(givenName)
-- 	local ic = require('component').inventory_controller
-- 	size = bot.inventorySize()
-- 	local flag = false
-- 	for i = 1, size do
-- 		local item = ic.getStackInInternalSlot(i)
-- 		if (item ~= nil) then
-- 			local itemName = item.name
-- 			if (itemName == givenName) then
-- 				Utils.select(i)
-- 				flag = true
-- 				break
-- 			end
-- 		end

-- 	end
-- 	if (flag == false) then
-- 		os.exit()
-- 	end
-- end

Utils.placeUp_S = function(blockName, numCheck, label, side)
    if (numCheck == nil) then
        numCheck = true
    end
    if (numCheck == true) then
        if (Utils.getTotalNumOf(blockName) == 0) then
            return false, "no enough specific blocks"
        end
    end
    local slotId = Utils.getSlotIdByItemName(blockName, label)
    while slotId == -1 do
        os.sleep(10)
        slotId = Utils.getSlotIdByItemName(blockName, label)
    end
    -- Utils.selectByName(blockName)

    Utils.select(
            slotId,
            1,
            function()
                while (bot.placeUp(side) == false) do
                    local a, b = bot.detectUp()
                    if (b == "solid") then
                        break
                    end
                    os.sleep(3)
                end
            end
    )

    -- selectLocked = 0
    return true
end
Utils.placeDown_S = function(blockName, numCheck, label, side)
    if (numCheck == nil) then
        numCheck = true
    end
    if (numCheck == true) then
        if (Utils.getTotalNumOf(blockName) == 0) then
            return false, "no enough specific blocks"
        end
    end

    -- Utils.selectByName(blockName)
    local slotId = Utils.getSlotIdByItemName(blockName, label)
    while slotId == -1 do
        os.sleep(10)
        slotId = Utils.getSlotIdByItemName(blockName, label)
    end

    Utils.select(
            slotId,
            1,
            function()
                while (bot.placeDown(side) == false) do
                    local a, b = bot.detectDown()
                    if (b == "solid") then
                        break
                    end
                    os.sleep(3)
                end
            end
    )

    -- selectLocked = 0
    return true
end
Utils.placeAhead_S = function(blockName, numCheck, label, side)
    if (numCheck == nil) then
        numCheck = true
    end
    if (numCheck == true) then
        if (Utils.getTotalNumOf(blockName) == 0) then
            return false, "no enough specific blocks"
        end
    end

    -- Utils.selectByName(blockName)
    local slotId = Utils.getSlotIdByItemName(blockName, label)
    while slotId == -1 do
        os.sleep(10)
        slotId = Utils.getSlotIdByItemName(blockName, label)
    end
    Utils.select(
            slotId,
            1,
            function()
                while (bot.place(side) == false) do
                    local a, b = bot.detect(sides.front)
                    if (b == "solid") then
                        break
                    end
                    os.sleep(3)
                end
            end
    )

    -- selectLocked = 0
    return true
end
Utils.placeLeft_S = function(blockName, numCheck, label, side)
    Utils.turnLeft()
    Utils.placeAhead_S(blockName, numCheck, label, side)
    Utils.turnRight()
end
Utils.placeRight_S = function(blockName, numCheck, label, side)
    Utils.turnRight()
    Utils.placeAhead_S(blockName, numCheck, label, side)
    Utils.turnLeft()
end
Utils.placeRight_SE = function(blockName, numCheck)
    local res, msg = Utils.placeRight_S(blockName, numCheck)
    if (res == false) then
        error(msg)
    end
end
Utils.placeLeft_SE = function(blockName, numCheck)
    local res, msg = Utils.placeLeft_S(blockName, numCheck)
    if (res == false) then
        error(msg)
    end
end

Utils.placeUp_SE = function(blockName, numCheck)
    local res, msg = Utils.placeUp_S(blockName, numCheck)
    if (res == false) then
        error(msg)
    end
end

Utils.placeAhead_SE = function(blockName, numCheck)
    local res, msg = Utils.placeAhead_S(blockName, numCheck)
    if (res == false) then
        error(msg)
    end
end

Utils.placeDown_SE = function(blockName, numCheck)
    local res, msg = Utils.placeDown_S(blockName, numCheck)
    if (res == false) then
        error(msg)
    end
end

Utils.placeHBar_S = function(blockName, length, ret, numCheck, forcePlacing)
    if (forcePlacing == nil) then
        forcePlacing = false
    end
    if (numCheck == nil) then
        numCheck = true
    end
    if (numCheck == true) then
        if (Utils.getTotalNumOf(blockName) < length) then
            return false, "no enough specific blocks"
        end
    end
    if (ret == nil) then
        ret = true
    end
    for i = 1, length do
        if (forcePlacing) then
            Utils.cleanDown()
        end
        Utils.placeDown_S(blockName, false)
        if (i < length) then
            if (forcePlacing) then
                Utils.cleanForward()
            end
            Utils.forward()
        end
    end
    if (ret) then
        Utils.back(length - 1)
    end
    return true
end
Utils.cleanDown = function()
    -- ?????????????????????????????????????????????????????
    local a, b = bot.detectDown()
    if (a == true) then
        -- ???????????????????????????
        if (b == "solid") then
            -- ????????????
            if (bot.swingDown() == false) then
                -- ?????????????????
                error("cannot break the block below")
            end
        elseif (b == "entity") then
            -- ???????????????

            os.sleep(3)
            Utils.cleanDown()
        end
    end
end
Utils.cleanForward = function()
    -- ?????????????????????????????????????????????????????
    local a, b = bot.detect()
    if (a == true) then
        -- ???????????????????????????
        if (b == "solid") then
            -- ????????????
            if (bot.swing() == false) then
                -- ?????????????????
                error("cannot break the block ahead")
            end
        elseif (b == "entity") then
            -- ???????????????

            os.sleep(3)
            Utils.cleanForward()
        end
    end
end
Utils.placeFloor_S = function(blockName, length, width, ret, numCheck)
    if (numCheck == nil) then
        numCheck = true
    end
    if (numCheck == true) then
        if (Utils.getTotalNumOf(blockName) < length * width) then
            return false, "no enough specific blocks"
        end
    end
    if (ret == nil) then
        ret = true
    end
    for i = 1, length do
        Utils.placeHBar_S(blockName, width, true, false)
        if (i < length) then
            Utils.moveRight()
        end
    end
    if (ret) then
        Utils.moveLeft(length - 1)
    end
    return true
end
Utils.buildRectangle_S = function(blockName, length, width, numCheck)
    if (numCheck == nil) then
        numCheck = true
    end
    if (numCheck == true) then
        if (Utils.getTotalNumOf(blockName) < 2 * (length + width) - 4) then
            return false, "no enough specific blocks"
        end
    end
    Utils.placeHBar_S(blockName, width, false, false) -- ??????
    Utils.turnRight()
    Utils.placeHBar_S(blockName, length, false, false)
    Utils.turnRight()
    Utils.placeHBar_S(blockName, width, false, false)
    Utils.turnRight()
    Utils.placeHBar_S(blockName, length, false, false)
    Utils.turnRight()
    return true
end
Utils.buildMultiLayerHC_S = function(blockName, length, width, height, layers, numCheck)
    if (layers == nil) then
        layers = 1
    end
    if (numCheck == nil) then
        numCheck = true
    end
    if (numCheck == true) then
        local x = Utils.getTotalNumOf(blockName) -
                (width * length + layers * (width * length + (height - 2) * (2 * (length + width) - 4)))

        if (x < 0) then
            return false, "still need " .. tostring(-x) .. "blocks"
        end
    end
    for i = 1, layers do
        Utils.buildHollowCuboid_S(blockName, length, width, height, numCheck)
    end
    return true
end

Utils.directlyBuildNuclearHouse = function(length, width, height, layers, opening, numCheck)
    local blockName = "ic2:resource"
    if opening == nil then
        opening = true
    end
    if (layers == nil) then
        layers = 1
    end
    if (numCheck == nil) then
        numCheck = true
    end
    -- if (fillBlockName == nil) then
    --     fillBlockName = "minecraft:log"
    -- end

    if (numCheck == true) then
        local x = Utils.getTotalNumOf(blockName) -
                (width * length + layers * (width * length + (height - 2) * (2 * (length + width) - 4)))

        if (x < 0) then
            return false, "still need " .. tostring(-x) .. "blocks"
        end
    end
    -- if (numCheck == true) then
    --     local y = Utils.getTotalNumOf(fillBlockName) - (width - 2) * (length - 2) * layers
    --     if (y < 0) then
    --         return false, "still need " .. tostring(-y) .. "blocks"
    --     end
    -- end
    for i = 1, layers do
        Utils.directlyBuildOneLayerNuclearHouse(length, width, height, opening, numCheck)
    end
    return true
end
Utils.buildNuclearHouse = function(fillBlockName, length, width, height, layers, opening, numCheck)
    local blockName = "ic2:scaffold"
    if opening == nil then
        opening = true
    end
    if (layers == nil) then
        layers = 1
    end
    if (numCheck == nil) then
        numCheck = true
    end
    if (fillBlockName == nil) then
        fillBlockName = "minecraft:log"
    end

    if (numCheck == true) then
        local x = Utils.getTotalNumOf(blockName) -
                (width * length + layers * (width * length + (height - 2) * (2 * (length + width) - 4)))

        if (x < 0) then
            return false, "still need " .. tostring(-x) .. "blocks"
        end
    end
    if (numCheck == true) then
        local y = Utils.getTotalNumOf(fillBlockName) - (width - 2) * (length - 2) * layers
        if (y < 0) then
            return false, "still need " .. tostring(-y) .. "blocks"
        end
    end
    for i = 1, layers do
        Utils.buildOneLayerNuclearHouse(fillBlockName, length, width, height, opening, numCheck)
    end
    return true
end
Utils.directlyBuildOneLayerNuclearHouse = function(length, width, height, opening, numCheck)
    local blockName = "ic2:resource"

    if (numCheck == nil) then
        numCheck = true
    end
    if (numCheck == true) then
        if (Utils.getTotalNumOf(blockName) < 2 * width * length + (height - 2) * (2 * (length + width) - 4)) then
            return false, "no enough specific blocks"
        end
    end
    for i = 1, height do
        if (i == 1 or i == height) then
            Utils.placeFloor_S(blockName, length, width, true, false)
        else
            if opening then
                if i == 2 or i == 4 then
                    Utils.placeHBar_S(blockName, width - 4, false, false)
                    Utils.forward(2)

                    Utils.placeHBar_S(blockName, 3, false, false)
                else
                    Utils.placeHBar_S(blockName, width, false, false)
                end
                Utils.turnRight()
                Utils.placeHBar_S(blockName, length, false, false)
                Utils.turnRight()
                Utils.placeHBar_S(blockName, width, false, false)
                Utils.turnRight()
                if (i == 2 or i == 3) then
                    Utils.forward(2)
                    Utils.placeHBar_S(blockName, length - 2, false, false)
                else
                    Utils.placeHBar_S(blockName, length, false, false)
                end
                Utils.turnRight()
            else
                Utils.buildRectangle_S(blockName, length, width, false)
            end

            -- if (i == height - 1) then
            --     Utils.moveRight(1)
            --     Utils.placeFloor_S(fillBlockName, length - 2, width, true, false)
            --     Utils.moveLeft(1)
            -- end
        end
        if (i ~= height) then
            Utils.up()
        end
    end

    --

    return true
end
Utils.buildOneLayerNuclearHouse = function(fillBlockName, length, width, height, opening, numCheck)
    local blockName = "ic2:scaffold"

    if (numCheck == nil) then
        numCheck = true
    end
    if (numCheck == true) then
        if (Utils.getTotalNumOf(blockName) < 2 * width * length + (height - 2) * (2 * (length + width) - 4)) then
            return false, "no enough specific blocks"
        end
    end
    for i = 1, height do
        if (i == 1 or i == height) then
            Utils.placeFloor_S(blockName, length, width, true, false)
        else
            if opening then
                if i == 2 or i == 4 then
                    Utils.placeHBar_S(blockName, width - 4, false, false)
                    Utils.forward(2)

                    Utils.placeHBar_S(blockName, 3, false, false)
                else
                    Utils.placeHBar_S(blockName, width, false, false)
                end
                Utils.turnRight()
                Utils.placeHBar_S(blockName, length, false, false)
                Utils.turnRight()
                Utils.placeHBar_S(blockName, width, false, false)
                Utils.turnRight()
                if (i == 2 or i == 3) then
                    Utils.forward(2)
                    Utils.placeHBar_S(blockName, length - 2, false, false)
                else
                    Utils.placeHBar_S(blockName, length, false, false)
                end
                Utils.turnRight()
            else
                Utils.buildRectangle_S(blockName, length, width, false)
            end

            if (i == height - 1) then
                Utils.moveRight(1)
                Utils.placeFloor_S(fillBlockName, length - 2, width, true, false)
                Utils.moveLeft(1)
            end
        end
        if (i ~= height) then
            Utils.up()
        end
    end

    --

    return true
end
Utils.buildHollowCuboid_S = function(blockName, length, width, height, numCheck)
    if (numCheck == nil) then
        numCheck = true
    end
    if (numCheck == true) then
        local res, msg = Utils.numCheck({ [blockName] = 2 * width * length + (height - 2) * (2 * (length + width) - 4) })
        if res == false then
            return res, msg
        end
        -- if (Utils.getTotalNumOf(blockName) < 2 * width * length + (height - 2) * (2 * (length + width) - 4)) then
        --     return false, "no enough specific blocks"
        -- end
    end
    for i = 1, height do
        if (i == 1 or i == height) then
            Utils.placeFloor_S(blockName, length, width, true, false)
        else
            Utils.buildRectangle_S(blockName, length, width, false)
        end
        if (i ~= height) then
            Utils.up()
        end
    end

    --

    return true
end
--[[
    机器人开始高度即为建筑最低高度
    相比原来的函数的区别：1.不铺地板 2.机器人先向上走一格
 ]]
Utils.buildHollowCuboidWithoutFloor_S = function(blockName, length, width, height, numCheck)
    if (numCheck == nil) then
        numCheck = true
    end
    if (numCheck == true) then
        local res, msg = Utils.numCheck({ [blockName] = width * length + (height - 1) * (2 * (length + width) - 4) })
        if res == false then
            return res, msg
        end
        -- if (Utils.getTotalNumOf(blockName) < 2 * width * length + (height - 2) * (2 * (length + width) - 4)) then
        --     return false, "no enough specific blocks"
        -- end
    end
    -- Utils.up()
    for i = 1, height do
        Utils.up()
        if (i == height) then
            Utils.placeFloor_S(blockName, length, width, true, false)
        else
            Utils.buildRectangle_S(blockName, length, width, false)
        end
        -- if (i ~= height) then
        --     Utils.up()
        -- end
    end

    --

    return true
end
Utils.buildCuboid_S = function(blockName, length, width, height, numCheck)
    if (numCheck == nil) then
        numCheck = true
    end
    if (numCheck == true) then
        if (Utils.getTotalNumOf(blockName) < length * width * height) then
            return false, "no enough specific blocks"
        end
    end
    for i = 1, height do
        Utils.placeFloor_S(blockName, length, width, true, false)
        if (i ~= height) then
            Utils.up()
        end
    end
    return true
end
--[[
?????????????????????????????????????
????????? count:????????
???????????????
????:????????????????
]]
-- Utils.burnFuel = function(count)
-- 	generator = require('component').generator
-- 	currentSlot = Utils.select() --???????????
-- 	size = bot.inventorySize()
-- 	if generator.count() + count > 64 then --??????????????????
-- 		count = 64 - generator.count()
-- 	end
-- 	success = false
-- 	for i = 1, size do --????????????????????????
-- 		Utils.select(i)
-- 		if (generator.insert(count)) then
-- 			success = true --
-- 			break --???????

-- 		end

-- 	end
-- 	Utils.select(currentSlot) --???????????
-- 	return success
-- end
Utils.fuelCount = function()
    generator = require("component").generator
    return generator.count()
end

Utils.cutWool = function(width, length, retain, neverStop, isRight, isAhead)
    if (isAhead == nil) then
        isAhead = true
    end
    if (isRight == nil) then
        isRight = true
    end
    if (retain == nil) then
        -- 默认会保留工具 Tools are retained by default
        retain = true
    end
    if neverStop == nil then
        -- 没有剪刀也要移动
        neverStop = true
    end
    -- if (automaticEquipment == nil) then --默认会自动装备,直到没有剪刀为止 By default, it will be equipped automatically until there are no scissors
    -- 	automaticEquipment = true
    -- end
    if (isAhead == false and isRight == false) then
        Utils.turnAround()
    elseif (isAhead == false and isRight == true) then
        Utils.turnRight()
        local temp = width
        width = length
        length = temp
    elseif (isAhead == true and isRight == false) then
        Utils.turnLeft()
        local temp = width
        width = length
        length = temp
    else
    end
    local ic = nil
    -- if (automaticEquipment) then
    -- if automaticEquipment is set to true, this function will check if the robot has inventory controller upgrade.if robot does't,this funtion will return 'no_inventory_controller_upgrade'.
    -- 如果AutomaticeEquipment设置为true，则此功能将检查机器人是否有库存控制器升级。如果机器人没有，则此功能将返回“no_inventory_controller_upgrade”。
    ic = require("component").inventory_controller
    if (ic == nil) then
        return "no_inventory_controller_upgrade"
    end
    -- end
    local extra = 0
    while (true) do
        local count = 0

        while (true) do
            count = count + 1

            for i = 1, length do
                -- if (com.energy() < 5000) then
                -- 	generator = require('component').generator
                -- 	if (generator ~= nil) then
                -- 		Utils.burnFuel(1)
                -- 	end
                -- end

                if (retain == true) then
                    if (bot.durability() == nil or bot.durability() < 0.05) then
                        local res = Utils.getFirstSlotIdWithConditions(
                                function(stack)
                                    if (stack == nil) then
                                        return false
                                    else
                                        if (stack.name == "minecraft:shears" and (1 - stack.damage / stack.maxDamage) > 0.1) then
                                            -- 除了检查名字，还会检查耐久度是否在0.1以上。
                                            return true
                                        else
                                            return false
                                        end
                                    end
                                end
                        )
                        if (res == -1) then
                            if not neverStop then
                                return "no shears or no shears with enough durability"
                            end
                        else
                            Utils.select(res, 1, ic.equip, true)
                        end
                    end
                else
                    if (bot.durability() == nil) then
                        local res = Utils.getSlotIdByItemName("minecraft:shears")
                        if (res == -1) then
                            if not neverStop then
                                return "not enough shears"
                            end
                        else
                            Utils.select(res, 1, ic.equip, true)
                        end
                    end
                end

                a, b = bot.detectDown()
                if (b == "entity") then
                    bot.useDown()
                end
                if (i < length) then
                    Utils.forward()
                end
            end

            if (count >= width) then
                Utils.turnAround()
                if (count % 2 == 0) then
                    extra = extra + 1
                end
                break
            elseif ((count + extra) % 2 == 0) then
                Utils.turnLeft()
                Utils.forward()
                Utils.turnLeft()
            else
                Utils.turnRight()
                Utils.forward()
                Utils.turnRight()
            end
        end
    end
end
Utils.cutWoolV2 = function(width, length, retain, neverStop)
    if (retain == nil) then
        -- 默认会保留工具 Tools are retained by default
        retain = true
    end
    if neverStop == nil then
        -- 没有剪刀也要移动
        neverStop = true
    end
    -- if (automaticEquipment == nil) then --默认会自动装备,直到没有剪刀为止 By default, it will be equipped automatically until there are no scissors
    -- 	automaticEquipment = true
    -- end
    local ic = Utils.getInventoryController()
    -- if (automaticEquipment) then
    -- if automaticEquipment is set to true, this function will check if the robot has inventory controller upgrade.if robot does't,this funtion will return 'no_inventory_controller_upgrade'.
    -- 如果AutomaticeEquipment设置为true，则此功能将检查机器人是否有库存控制器升级。如果机器人没有，则此功能将返回“no_inventory_controller_upgrade”。

    if (ic == nil) then
        return false, "no_inventory_controller_upgrade"
    end
    -- end
    -- local extra = 0
    while true do
        Utils.turnLeft()
        Utils.ForEachNotNilInternalInventory(function(slot, stack)
            if stack.name == 'minecraft:wool' then
                Utils.select(slot, 1, function()
                    bot.drop()
                end)
            end
        end)
        Utils.turnRight()
        Utils.select(Utils.getSlotIdByItemName('minecraft:wheat_seeds'))
        for i = 1, width do
            for j = 1, length do
                if (retain == true) then
                    if (bot.durability() == nil or bot.durability() < 0.05) then
                        local res = Utils.getFirstSlotIdWithConditions(
                                function(stack)
                                    if (stack == nil) then
                                        return false
                                    else
                                        if (stack.name == "minecraft:shears" and (1 - stack.damage / stack.maxDamage) > 0.1) then
                                            -- 除了检查名字，还会检查耐久度是否在0.1以上。
                                            return true
                                        else
                                            return false
                                        end
                                    end
                                end
                        )
                        if (res == -1) then
                            if not neverStop then
                                return "no shears or no shears with enough durability"
                            end
                        else
                            Utils.select(res, 1, ic.equip, true)
                        end
                    end
                else
                    if (bot.durability() == nil) then
                        local res = Utils.getSlotIdByItemName("minecraft:shears")
                        if (res == -1) then
                            if not neverStop then
                                return "not enough shears"
                            end
                        else
                            Utils.select(res, 1, ic.equip, true)
                        end
                    end
                end

                a, b = bot.detectDown()
                if (b == "entity") then
                    bot.useDown()
                end
                -- if (i < length) then
                --     Utils.forward()
                -- end
                if j < length then
                    Utils.forward()
                end
            end
            for j = 1, length do
                if (retain == true) then
                    if (bot.durability() == nil or bot.durability() < 0.05) then
                        local res = Utils.getFirstSlotIdWithConditions(
                                function(stack)
                                    if (stack == nil) then
                                        return false
                                    else
                                        if (stack.name == "minecraft:shears" and (1 - stack.damage / stack.maxDamage) > 0.1) then
                                            -- 除了检查名字，还会检查耐久度是否在0.1以上。
                                            return true
                                        else
                                            return false
                                        end
                                    end
                                end
                        )
                        if (res == -1) then
                            if not neverStop then
                                return "no shears or no shears with enough durability"
                            end
                        else
                            Utils.select(res, 1, ic.equip, true)
                        end
                    end
                else
                    if (bot.durability() == nil) then
                        local res = Utils.getSlotIdByItemName("minecraft:shears")
                        if (res == -1) then
                            if not neverStop then
                                return "not enough shears"
                            end
                        else
                            Utils.select(res, 1, ic.equip, true)
                        end
                    end
                end

                a, b = bot.detectDown()
                if (b == "entity") then
                    bot.useDown()
                end
                -- if (i < length) then
                --     Utils.forward()
                -- end
                if j < length then
                    Utils.back()
                end
            end

            if i < width then
                Utils.moveRight()
            end
        end

        Utils.moveLeft(width - 1)
    end
end

Utils.cutWoolFullyAutomatic = function(width, length, fuel, fuel_keep_num, shears_keep_num)
    local shears = 'minecraft:shears'

    if fuel == nil then
        fuel = 'forestry:charcoal'
    end
    if fuel_keep_num == nil then
        fuel_keep_num = 64
    end
    if shears_keep_num == nil then
        shears_keep_num = 4
    end
    local retain = false
    local neverStop = true
    -- if (automaticEquipment == nil) then --默认会自动装备,直到没有剪刀为止 By default, it will be equipped automatically until there are no scissors
    -- 	automaticEquipment = true
    -- end
    local ic = Utils.getInventoryController()
    -- if (automaticEquipment) then
    -- if automaticEquipment is set to true, this function will check if the robot has inventory controller upgrade.if robot does't,this funtion will return 'no_inventory_controller_upgrade'.
    -- 如果AutomaticeEquipment设置为true，则此功能将检查机器人是否有库存控制器升级。如果机器人没有，则此功能将返回“no_inventory_controller_upgrade”。

    if (ic == nil) then
        return false, "no_inventory_controller_upgrade"
    end
    -- end
    -- local extra = 0
    while true do
        Utils.select(Utils.getSlotIdByItemName('minecraft:wheat_seeds'))
        Utils.turnLeft()
        Utils.ForEachNotNilInternalInventory(function(slot, stack)
            if stack.name == 'minecraft:wool' then
                Utils.select(slot, 1, function()
                    bot.drop()
                end, true)
            end
        end)
        Utils.turnLeft()
        local need_shears_num = shears_keep_num - Utils.getTotalNumOf(shears)
        if need_shears_num > 0 then
            Utils.suckSpecifiedNumofItemsWithSide(sides.forward, shears, need_shears_num)
        end
        Utils.turnAround()
        local need_fuel_num = fuel_keep_num - Utils.getTotalNumOf(fuel)
        if need_fuel_num > 0 then
            Utils.suckSpecifiedNumofItemsWithSide(sides.up, fuel, need_fuel_num)
        end
        for i = 1, width do
            for j = 1, length do
                if (retain == true) then
                    if (bot.durability() == nil or bot.durability() < 0.05) then
                        local res = Utils.getFirstSlotIdWithConditions(
                                function(stack)
                                    if (stack == nil) then
                                        return false
                                    else
                                        if (stack.name == "minecraft:shears" and (1 - stack.damage / stack.maxDamage) > 0.1) then
                                            -- 除了检查名字，还会检查耐久度是否在0.1以上。
                                            return true
                                        else
                                            return false
                                        end
                                    end
                                end
                        )
                        if (res == -1) then
                            if not neverStop then
                                return "no shears or no shears with enough durability"
                            end
                        else
                            Utils.select(res, 1, ic.equip, true)
                        end
                    end
                else
                    if (bot.durability() == nil) then
                        local res = Utils.getSlotIdByItemName("minecraft:shears")
                        if (res == -1) then
                            if not neverStop then
                                return "not enough shears"
                            end
                        else
                            Utils.select(res, 1, ic.equip, true)
                        end
                    end
                end

                a, b = bot.detectDown()
                if (b == "entity") then
                    bot.useDown()
                end
                -- if (i < length) then
                --     Utils.forward()
                -- end
                if j < length then
                    Utils.forward()
                end
            end
            for j = 1, length do
                if (retain == true) then
                    if (bot.durability() == nil or bot.durability() < 0.05) then
                        local res = Utils.getFirstSlotIdWithConditions(
                                function(stack)
                                    if (stack == nil) then
                                        return false
                                    else
                                        if (stack.name == "minecraft:shears" and (1 - stack.damage / stack.maxDamage) > 0.1) then
                                            -- 除了检查名字，还会检查耐久度是否在0.1以上。
                                            return true
                                        else
                                            return false
                                        end
                                    end
                                end
                        )
                        if (res == -1) then
                            if not neverStop then
                                return "no shears or no shears with enough durability"
                            end
                        else
                            Utils.select(res, 1, ic.equip, true)
                        end
                    end
                else
                    if (bot.durability() == nil) then
                        local res = Utils.getSlotIdByItemName("minecraft:shears")
                        if (res == -1) then
                            if not neverStop then
                                return "not enough shears"
                            end
                        else
                            Utils.select(res, 1, ic.equip, true)
                        end
                    end
                end

                a, b = bot.detectDown()
                if (b == "entity") then
                    bot.useDown()
                end
                -- if (i < length) then
                --     Utils.forward()
                -- end
                if j < length then
                    Utils.back()
                end
            end

            if i < width then
                Utils.moveRight()
            end
        end

        Utils.moveLeft(width - 1)
    end
end

Utils.swing = function(autoShutdown)
    if (autoShutdown == nil) then
        autoShutdown = true
    end
    if (autoShutdown == false) then
        return bot.swing()
    end
    if (bot.durability() < 0.05) then
        error("not enough durability")
    else
        return bot.swing()
    end
end
Utils.swingDown = function(autoShutdown)
    if (autoShutdown == nil) then
        autoShutdown = true
    end
    if (autoShutdown == false) then
        return bot.swingDown()
    end
    if (bot.durability() < 0.05) then
        error("not enough durability")
    else
        return bot.swingDown()
    end
end
Utils.swingUp = function(autoShutdown)
    if (autoShutdown == nil) then
        autoShutdown = true
    end
    if (autoShutdown == false) then
        return bot.swingUp()
    end
    if (bot.durability() < 0.05) then
        error("not enough durability")
    else
        return bot.swingUp()
    end
end
Utils.mySwing = function(length, width, height)
    for i = 1, height do
        for j = 1, length do
            for k = 1, width do
                bot.swingDown()
                if (k ~= width) then
                    Utils.forward()
                end
            end
            Utils.back(width - 1)
            if (j ~= length) then
                Utils.moveRight()
            end
        end
        Utils.moveLeft(length - 1)
        Utils.down()
    end
end
Utils.swingTunnel = function(width, height, length, fixBlockName, itemNumCheck, autoShutdown, torchDis, bothSideTorch)
    if (bothSideTorch == nil) then
        bothSideTorch = false
    end
    if (autoShutdown == nil) then
        autoShutdown = true
    end
    if (itemNumCheck == nil) then
        itemNumCheck = true -- ?????????????
    end
    if (length == nil or length < 0) then
        length = 10000000
    end
    for i = 1, length do
        Utils.swing(autoShutdown)
        Utils.forward(1, true)
        for j = 1, width do
            for k = 1, height do
                if width == 1 and height == 1 then
                    if j == 1 and k == 1 then
                        Utils.placeUp_SE(fixBlockName, itemNumCheck)
                        Utils.placeDown_SE(fixBlockName, itemNumCheck)
                        Utils.placeLeft_SE(fixBlockName, itemNumCheck)
                        Utils.placeRight_SE(fixBlockName, itemNumCheck)
                        Utils.placeAhead_SE(fixBlockName, itemNumCheck)
                    end
                elseif width == 1 then
                    if k == 1 then
                        Utils.placeUp_SE(fixBlockName, itemNumCheck)
                        -- Utils.placeDown_SE(fixBlockName, itemNumCheck)
                        Utils.placeLeft_SE(fixBlockName, itemNumCheck)
                        Utils.placeRight_SE(fixBlockName, itemNumCheck)
                        Utils.placeAhead_SE(fixBlockName, itemNumCheck)
                    elseif k == height then
                        -- Utils.placeUp_SE(fixBlockName, itemNumCheck)
                        Utils.placeDown_SE(fixBlockName, itemNumCheck)
                        Utils.placeLeft_SE(fixBlockName, itemNumCheck)
                        Utils.placeRight_SE(fixBlockName, itemNumCheck)
                        Utils.placeAhead_SE(fixBlockName, itemNumCheck)
                    else
                        -- Utils.placeUp_SE(fixBlockName, itemNumCheck)
                        -- Utils.placeDown_SE(fixBlockName, itemNumCheck)
                        Utils.placeLeft_SE(fixBlockName, itemNumCheck)
                        Utils.placeRight_SE(fixBlockName, itemNumCheck)
                        Utils.placeAhead_SE(fixBlockName, itemNumCheck)
                    end
                elseif height == 1 then
                    if j == 1 then
                        Utils.placeUp_SE(fixBlockName, itemNumCheck)
                        Utils.placeDown_SE(fixBlockName, itemNumCheck)
                        Utils.placeLeft_SE(fixBlockName, itemNumCheck)
                        -- Utils.placeRight_SE(fixBlockName, itemNumCheck)
                        Utils.placeAhead_SE(fixBlockName, itemNumCheck)
                    elseif j == width then
                        Utils.placeUp_SE(fixBlockName, itemNumCheck)
                        Utils.placeDown_SE(fixBlockName, itemNumCheck)
                        -- Utils.placeLeft_SE(fixBlockName, itemNumCheck)
                        Utils.placeRight_SE(fixBlockName, itemNumCheck)
                        Utils.placeAhead_SE(fixBlockName, itemNumCheck)
                    else
                        Utils.placeUp_SE(fixBlockName, itemNumCheck)
                        Utils.placeDown_SE(fixBlockName, itemNumCheck)
                        -- Utils.placeLeft_SE(fixBlockName, itemNumCheck)
                        -- Utils.placeRight_SE(fixBlockName, itemNumCheck)
                        Utils.placeAhead_SE(fixBlockName, itemNumCheck)
                    end
                else
                    if (j == 1 and k == 1) then
                        Utils.placeUp_SE(fixBlockName, itemNumCheck)
                        Utils.placeAhead_SE(fixBlockName, itemNumCheck)
                        Utils.placeLeft_SE(fixBlockName, itemNumCheck)
                    elseif (j == 1 and k == height) then
                        Utils.placeAhead_SE(fixBlockName, itemNumCheck)
                        Utils.placeLeft_SE(fixBlockName, itemNumCheck)
                        Utils.placeDown_SE(fixBlockName, itemNumCheck)
                    elseif (j == width and k == height) then
                        Utils.placeRight_SE(fixBlockName, itemNumCheck)
                        Utils.placeDown_SE(fixBlockName, itemNumCheck)
                        Utils.placeAhead_SE(fixBlockName, itemNumCheck)
                    elseif (j == width and k == 1) then
                        Utils.placeRight_SE(fixBlockName, itemNumCheck)
                        Utils.placeUp_SE(fixBlockName, itemNumCheck)
                        Utils.placeAhead_SE(fixBlockName, itemNumCheck)
                    elseif (j == 1) then
                        Utils.placeLeft_SE(fixBlockName, itemNumCheck)
                        Utils.placeAhead_SE(fixBlockName, itemNumCheck)
                    elseif (j == width) then
                        Utils.placeRight_SE(fixBlockName, itemNumCheck)
                        Utils.placeAhead_SE(fixBlockName, itemNumCheck)
                    elseif (k == 1) then
                        Utils.placeAhead_SE(fixBlockName, itemNumCheck)
                        Utils.placeUp_SE(fixBlockName, itemNumCheck)
                    elseif (k == height) then
                        Utils.placeAhead_S(fixBlockName, itemNumCheck)
                        Utils.placeDown_SE(fixBlockName, itemNumCheck)
                    else
                        Utils.placeAhead_S(fixBlockName, itemNumCheck)
                    end
                end

                if (k < height) then
                    Utils.swingDown(autoShutdown)
                    Utils.down(1, true)
                end
            end
            Utils.up(height - 1, true)
            Utils.placeUp_SE(fixBlockName, itemNumCheck)
            if (j < width) then
                Utils.turnRight()
                Utils.swing(autoShutdown)
                Utils.forward(1, true)
                Utils.turnLeft()
            end
        end
        if (torchDis ~= nil) then
            if (i % torchDis == 0) then
                Utils.turnAround()
                Utils.down()
                Utils.placeAhead_SE("minecraft:torch", itemNumCheck)
                Utils.up()
                Utils.turnAround()
            end
        end
        Utils.moveLeft(width - 1, true)
        if (bothSideTorch) then
            if (torchDis ~= nil) then
                if (i % torchDis == 0) then
                    Utils.turnAround()
                    Utils.down()
                    Utils.placeAhead_SE("minecraft:torch", itemNumCheck)
                    Utils.up()
                    Utils.turnAround()
                end
            end
        end

    end
end
Utils.my2x1Tunnel = function(length, torchDis)
    if (length == nil) then
        length = -1
    end
    Utils.swingTunnel(1, 2, length, "minecraft:cobblestone", false, false, torchDis)
end
Utils.myTunnel = function(length, torchDis)
    if (length == nil) then
        length = -1
    end
    Utils.swingTunnel(3, 3, length, "minecraft:cobblestone", false, false, torchDis)
end

Utils.myRail = function(length)
    if (length == nil or length < 0) then
        length = 10000000
    end
    for j = 1, length do
        if (j % 38 ~= 0) then
            Utils.placeDown_S("minecraft:rail", false)
        end
        if (j % 9 == 0 and j % 38 == 0) then
            Utils.placeDown_S("minecraft:golden_rail", false)
            Utils.moveRight()
            Utils.placeDown_S("minecraft:redstone_torch", false)
            Utils.moveLeft()
            Utils.turnRight()
            Utils.placeAhead_S("minecraft:torch")
            Utils.turnLeft()
        elseif (j % 9 == 0) then
            Utils.turnRight()
            Utils.placeAhead_S("minecraft:torch")
            Utils.turnLeft()
        elseif (j % 38 == 0) then
            Utils.placeDown_S("minecraft:golden_rail", false)
            Utils.moveRight()
            Utils.placeDown_S("minecraft:redstone_torch", false)
            Utils.moveLeft()
        end
        Utils.forward()
    end
end
--[[
    useItemName 用于交易的物品名，即交易框中左边的，nil时表示不限制
    name 交易得到的物品名，即交易框中右边的，一定要指定
    times 交易次数，在交易表中寻找满足条件的交易并交易(无论成功与否)计为一次
    dynamicTable 每次交易之前是否更新交易表(对内存有一定的要求)
    minA 一次交易中，用于交易的物品的个数最小值，小于此值的交易不符条件
    maxA 一次交易中，用于交易的物品的个数最大值，大于此值的交易不符条件
    minB 一次交易中，交易得到的物品的个数最小值，小于此值的交易不符条件
    maxB 一次交易中，交易得到的物品的个数最大值，大于此值的交易不符条件
    unstoppable 如果在某一次交易中因为各种原因交易失败，则不再进行后续次数的交易，返回false,msg
 ]]
Utils.Buy = function(useItemName, name, times, dynamicTable, minA, maxA, minB, maxB, unstoppable)
    -- ????times???????name?????(???????????????)
    -- dynamicTable???????????????????????
    local trades = require("component").trading.getTrades()
    if (unstoppable == nil) then
        unstoppable = false
    end
    if (times == nil or times < 0) then
        times = 10000000
    end

    if (minA == nil) then
        minA = 1
    end
    if (maxA == nil) then
        maxA = 1000000
    end
    if (minB == nil) then
        minB = 1
    end
    if (maxB == nil) then
        maxB = 1000000
    end
    for i = 1, times do
        if (dynamicTable) then
            trades = require("component").trading.getTrades()
        end
        local bought = false -- ??????????????????
        for key, value in ipairs(trades) do
            if (useItemName ~= nil) then
                local input = value.getInput()
                local output = value.getOutput()
                if (
                        value.isEnabled() and input.name == useItemName and output.name == name and input.size >= minA and
                                input.size <= maxA and
                                output.size >= minB and
                                output.size <= maxB)
                then
                    local res, msg = value.trade()
                    if (res == false) then
                        -- ???????????????????????????????????????????????????????????????????????????
                        -- if(unstoppable==false)then
                        -- 	return res, 'no goods'
                        -- end
                    else
                        -- ????????????????
                        bought = true
                        break
                    end
                end
            else
                -- ????????????????????????????????????????????????????????????????????
                local input = value.getInput()
                local output = value.getOutput()
                if (value.isEnabled() and output.name == name and output.size >= minB and output.size <= maxB) then
                    local res, msg = value.trade()
                    if (res == false) then
                        -- ??????????????????????????????
                        -- return false,msg
                    else
                        -- ????????????????
                        bought = true
                        break
                    end
                end
            end
        end
        if (bought == false) then
            -- ???????????????????????????
            if not unstoppable then
                return false, "no specified enabled trading found"
            end
        end
    end
    return true
end
--[[
    购买v2版本。
    此函数仅购买一次。
    只针对一个村民。多村民时不要使用。
    useItemName 用于交易的物品名，即交易框中左边的，一定要指定
    name 交易得到的物品名，即交易框中右边的，一定要指定
 ]]
Utils.Buyv2 = function(useItemName, name)
    local trades = require("component").trading.getTrades()

    for key, value in ipairs(trades) do
        local input = value.getInput()
        local output = value.getOutput()
        if input.name == useItemName and output.name == name then
            --[[
                    三种情况
                    第一种情况：机器人物品不够，无法兑换
                    第二种情况：此交易无货
                    第三种情况：兑换成功
                ]]
            local res, msg = value.trade()
            return res, msg
        end
    end
end
Utils.BuyEmeraldUsingEverything = function(dynamic, unstoppable)
    return Utils.Buy(nil, "minecraft:emerald", -1, dynamic, nil, nil, nil, nil, unstoppable)
end
Utils.BuySpecifiedThingUsingEmerald = function(name, times, dynamic, minA, maxA, minB, maxB)
    return Utils.Buy("minecraft:emerald", name, times, dynamic, minA, maxA, minB, maxB)
end
Utils.BuyGlowStone = function(times, dynamic, minB, maxB)
    return Utils.BuySpecifiedThingUsingEmerald("minecraft:glowstone", times, dynamic, nil, nil, minB, maxB)
end
Utils.getTrades = function()
    return require("component").trading.getTrades()
end
Utils.findSpecifiedTrading = function(trades, AName, ANum, BName, BNum, enchanted)
    sati = {}
    for key, value in ipairs(trades) do
        if (enchanted) then
            if (value.getOutput().enchantments ~= nil) then
                if (AName == nil and ANum == nil) then
                    if (value.getOutput().enchantments[1].name == BName and value.getOutput().size == BNum) then
                        table.insert(sati, key)
                    end
                else
                    if (value.getInput().name == AName and value.getInput().size == ANum and
                            value.getOutput().enchantments[1].name == BName and
                            value.getOutput().size == BNum)
                    then
                        table.insert(sati, key)
                    end
                end
            end
        else
            if (AName == nil and ANum == nil) then
                if (value.getOutput().name == BName and value.getOutput().size == BNum) then
                    table.insert(sati, key)
                end
            else
                if (value.getInput().name == AName and value.getInput().size == ANum and
                        value.getOutput().name == BName and
                        value.getOutput().size == BNum)
                then
                    table.insert(sati, key)
                end
            end
        end
    end
    return sati
end
Utils.buyEnchantedBook = function(enchantmentName, count, minLevel, maxLevel)
    if (count == nil or count < 0) then
        count = 10000000
    end
    if (minLevel == nil) then
        minLevel = 1
    end
    if (maxLevel == nil) then
        maxLevel = 10000000
    end
    trades = require("component").trading.getTrades()
    local dynamicTable = false
    for i = 1, count do
        if (dynamicTable) then
            trades = require("component").trading.getTrades()
        end
        local bought = false -- ??????????????????
        for key, value in ipairs(trades) do
            output = value.getOutput()
            if (output.name == "minecraft:enchanted_book" and value.isEnabled()) then
                if (output.enchantments[1].name == enchantmentName and output.enchantments[1].level >= minLevel and
                        output.enchantments[1].level <= maxLevel)
                then
                    local res, msg = value.trade()
                    if (res == false) then
                        -- ?????????????????,??????????
                        return false, "not enough emerald or book"
                    else
                        -- ????????????????
                        bought = true
                        break
                    end
                end
            end
        end
        if (bought == false) then
            return false, "no specified book available"
        end
    end
end
Utils.mushi = function()
    while (true) do
        local a1, b1 = Utils.Buy("minecraft:rotten_flesh", "minecraft:emerald", 20, false)
        local a2, b2 = Utils.Buy("minecraft:gold_ingot", "minecraft:emerald", 8, false)
        local a3, b3 = Utils.BuyGlowStone(100, false, 2, 3)
        if (b1 == "no goods" and b2 == "no goods" and (b3 == "no goods" or b3 == "no specified trading found")) then
            break
        end
    end
end
Utils.muitiLine = function(name, fbLen, fbNum, fb2fb, Left, forceMoving, back)
    if (fbLen * fbNum > Utils.getTotalNumOf(name)) then
        return false, "not enough blocks"
    end
    for i = 1, fbNum do
        Utils.placeHBar_S(name, fbLen, true, false)
        if (i < fbNum) then
            if (Left) then
                Utils.turnLeft()
            else
                Utils.turnRight()
            end

            Utils.forward(fb2fb, forceMoving)
            if (Left) then
                Utils.turnRight()
            else
                Utils.turnLeft()
            end
        end
    end
    if (back) then
        Utils.moveLeft(fbNum * fb2fb - 1)
    end
    return true
end
Utils.lvxian = function()
    return Utils.muitiLine("galacticraftcore:aluminum_wire", 600, 5, 240, false, true, false)
end

Utils.shuashi = function(num, sec, isAhead)
    if (isAhead == nil) then
        isAhead = false
    end
    for i = 1, num do
        if (isAhead) then
            bot.swing()
        else
            bot.swingDown()
        end

        os.sleep(2)
    end
    return true
end
Utils.cutCactus = function(width, length, waitSec, isRight, isAhead)
    if (waitSec == nil) then
        waitSec = 300
    end
    if (isAhead == nil) then
        isAhead = true
    end
    if (isRight == nil) then
        isRight = true
    end

    if (isAhead == false and isRight == false) then
        Utils.turnAround()
    elseif (isAhead == false and isRight == true) then
        Utils.turnRight()
        local temp = width
        width = length
        length = temp
    elseif (isAhead == true and isRight == false) then
        Utils.turnLeft()
        local temp = width
        width = length
        length = temp
    end
    while (true) do
        for i = 1, width do
            for j = 1, length do
                bot.swingDown()
                Utils.down()
                bot.swingDown()
                Utils.up()
                -- checkEnergy
                -- Utils.checkEnergy()
                --
                if (j < length) then
                    Utils.forward(2)
                end
            end
            Utils.back(2 * length - 2)

            if (i < width) then
                Utils.moveRight(2)
            end
        end
        Utils.moveLeft(2 * width - 2)
        os.sleep(waitSec)
    end
end

Utils.backgroundEnergyCheck = function(fuel_name, warning_percentage, loop_time)
    local g = require("component").generator
    if (g == nil) then
        -- ????????????????????????
        return nil, "no generator upgrade"
    end
    local ic = require("component").inventory_controller
    if (ic == nil) then
        -- ??????????????????????????????
        return nil, "no inventory_controller upgrade"
    end

    if (fuel_name == nil) then
        if Utils.itemExist('forestry:charcoal') then
            fuel_name = "forestry:charcoal"
        elseif Utils.itemExist('minecraft:coal_block') then
            fuel_name = "minecraft:coal_block"
        else
            return nil, 'Unspecified fuel type'
        end
    end
    if (warning_percentage == nil) then
        warning_percentage = 0.5
    end
    if (loop_time == nil) then
        loop_time = 10
    end

    local thread_handle = thread.create(
            function(a, b, c)
                while (true) do
                    -- print("debug3")
                    if (com.energy() / com.maxEnergy() <= b) then
                        -- print("debug4")
                        if (g.count() == 0) then
                            -- print("debug5")
                            ------
                            local res, msg = Utils.getSlotIdByItemName(a)
                            if res ~= nil and res ~= -1 then
                                Utils.select(
                                        res,
                                        2,
                                        function()
                                            g.insert(1)
                                        end,
                                        true
                                )
                            end

                            -- print("debug6")

                            -- selectLocked = 0
                        end
                    end
                    os.sleep(c)
                end
            end,
            fuel_name,
            warning_percentage,
            loop_time
    )
    thread_handle:detach()
    return thread_handle
end
-- Utils.getSlotIdByItemNameAndLabel=function (item_name,label)

-- 	-- local formerSlot=Utils.select()--???????????
-- 	local size = bot.inventorySize()
-- 	local ic = require('component').inventory_controller
-- 	if (ic == nil) then --??????????????????????????????
-- 		return nil, "no inventory_controller upgrade"
-- 	end
-- 	for i = 1, size do
-- 		local stack = ic.getStackInInternalSlot(i)
-- 		if (stack ~= nil and stack.name == item_name and stack.label==label) then
-- 			return i
-- 		end
-- 	end
-- 	return -1, "no such thing named " .. item_name
-- end
-- ???????????????????????
-- ????nil,'errmsg'?????????????
-- ????-1,?????????????????
-- ????????????????????????????????
Utils.getSlotIdByItemName = function(item_name, label)
    -- local formerSlot=Utils.select()--???????????
    local size = bot.inventorySize()
    local ic = require("component").inventory_controller
    if (ic == nil) then
        -- ??????????????????????????????
        return nil, "no inventory_controller upgrade"
    end
    for i = 1, size do
        local stack = ic.getStackInInternalSlot(i)
        if (stack ~= nil and stack.name == item_name) then
            if (label ~= nil) then
                if stack.label == label then
                    return i
                end
            else
                return i
            end
        end
    end
    if label == nil then
        return -1, "no such thing named " .. item_name
    else
        return -1, "no such thing named " .. item_name .. " and labeled " .. label
    end
end
Utils.regularlyDrainAndFill = function(sleepTime, drainDeltaTime, fillDeltaTime)
    if sleepTime == nil then
        sleepTime = 0
    end
    if drainDeltaTime == nil then
        drainDeltaTime = 0
    end
    if fillDeltaTime == nil then
        fillDeltaTime = 0
    end
    -- local a,b=nil,nil
    while true do
        while bot.tankSpace() >= 1000 do
            bot.drain()
            os.sleep(drainDeltaTime)
        end
        -- bot.drain()
        Utils.turnAround()
        while bot.tankLevel() >= 1000 do
            bot.fill()
            os.sleep(fillDeltaTime)
        end

        os.sleep(sleepTime)
        Utils.turnAround()
    end
end

Utils.getFirstSlotIdWithConditions = function(conditionCallback)
    -- 获取第一个满足conditionCallback回调函数的slotId
    local size = bot.inventorySize()
    local ic = require("component").inventory_controller
    if (ic == nil) then
        -- ??????????????????????????????
        return nil, "no inventory_controller upgrade"
    end
    for i = 1, size do
        local stack = ic.getStackInInternalSlot(i)
        if (conditionCallback(stack)) then
            return i
        end
    end
    return -1, "There is nothing like this that satisfies the given condition"
end
Utils.getFirstSlotIdWithIdConditions = function(conditionCallback)
    -- 获取第一个满足conditionCallback回调函数的slotId
    local size = bot.inventorySize()
    local ic = require("component").inventory_controller
    if (ic == nil) then
        -- ??????????????????????????????
        return nil, "no inventory_controller upgrade"
    end
    for i = 1, size do
        local stack = ic.getStackInInternalSlot(i)
        if (conditionCallback(i, stack)) then
            return i
        end
    end
    return -1, "There is nothing like this that satisfies the given condition"
end
local function k_include(tab, value)
    for k, v in pairs(tab) do
        if k == value then
            return true
        end
    end
    return false
end

--[[
	按照name_arr二维数组进行核反应堆散热片的摆放
	name_arr中为nil的地方不摆放
	By name_ ARR two-dimensional array for placement of nuclear reactor radiator
	
 ]]
Utils.placeNuclearRadiatorWithGivenNameArray = function(name_arr)
    if require("component").inventory_controller == nil then
        return false, "no inventory_controller_upgrade"
    end
    name_num_table = {}
    -- 统计各物品出现的频数
    for i = 1, 6 do
        for j = 1, 9 do
            if name_arr[i][j] ~= nil then
                if not k_include(name_num_table, name_arr[i][j]) then
                    name_num_table[name_arr[i][j]] = 0
                end
                name_num_table[name_arr[i][j]] = name_num_table[name_arr[i][j]] + 1
            end
        end
    end
    for k, v in pairs(name_num_table) do
        -- 材料数量检查
        if Utils.getTotalNumOf(k) < v then
            return false, "not enough " .. k
        end
    end
    for i = 1, 6 do
        for j = 1, 9 do
            if name_arr[i][j] ~= nil then
                Utils.placeNuclear(name_arr[i][j], j, i)
            end
        end
    end
    return true
end
Utils.placeNuclearRadiatorFor360EU = function(need_plating)
    if (need_plating == nil) then
        need_plating = true
    end
    local o = "ic2:overclocked_heat_vent"
    local c = "ic2:component_heat_vent"
    local p = "ic2:plating"
    local n = nil
    local name_arr = {}
    if (need_plating) then
        table.insert(name_arr, { c, o, p, c, o, p, c, o, p })
        table.insert(name_arr, { o, n, o, o, n, o, o, n, o })
        table.insert(name_arr, { p, o, c, p, o, c, p, o, c })
        table.insert(name_arr, { c, o, p, c, o, p, c, o, p })
        table.insert(name_arr, { o, n, o, o, n, o, o, n, o })
        table.insert(name_arr, { p, o, c, p, o, c, p, o, c })
    else
        table.insert(name_arr, { c, o, n, c, o, n, c, o, n })
        table.insert(name_arr, { o, n, o, o, n, o, o, n, o })
        table.insert(name_arr, { n, o, c, n, o, c, n, o, c })
        table.insert(name_arr, { c, o, n, c, o, n, c, o, n })
        table.insert(name_arr, { o, n, o, o, n, o, o, n, o })
        table.insert(name_arr, { n, o, c, n, o, c, n, o, c })
    end

    return Utils.placeNuclearRadiatorWithGivenNameArray(name_arr)
end
Utils.placeNuclearRadiatorFor1350EU = function()
    -- if (need_plating == nil) then
    -- 	need_plating = true
    -- end
    local c = "ic2:component_heat_vent"
    local a = "ic2:advanced_heat_vent"
    local e = "ic2:component_heat_exchanger"
    -- local res,msg=Utils.numCheck({[c]= 11,[a]= 27,[e]= 11})
    -- if res==false then
    -- 	return res,msg
    -- end
    local n = nil
    local name_arr = {}

    table.insert(name_arr, { n, a, c, a, c, a, c, a, n })
    table.insert(name_arr, { a, e, a, e, a, e, a, e, a })
    table.insert(name_arr, { c, a, c, a, n, a, c, a, c })
    table.insert(name_arr, { a, e, a, e, a, c, a, e, a })
    table.insert(name_arr, { n, a, c, a, c, a, c, a, n })
    table.insert(name_arr, { a, e, a, e, a, e, a, e, a })

    return Utils.placeNuclearRadiatorWithGivenNameArray(name_arr)
end
--[[
	机器人向面前的核反应堆的x,y处放置一个在自己物品栏里的、名为itemName的物品
	成功返回true
	失败返回false,'错误信息'
	The robot places an item named itemName in its own item list at x and y of the nuclear reactor in front of it
	Returns true if successful
	Failure returns false, 'error message'
 ]]
Utils.placeNuclear = function(itemName, x, y)
    -- x 和 y 从 1 开始
    local ic = require("component").inventory_controller
    local sides = require("sides")
    if ic == nil then
        return false, "no inventory_controller_upgrade"
    end
    local res = Utils.getSlotIdByItemName(itemName)
    if res == -1 then
        -- 如果机器人的物品栏没有这种物品的话 If there is no such item in the robot's inventory
        return false, "no such item named " .. itemName .. " in the robot's inventory"
    else
        local res2
        Utils.select(
                res,
                1,
                function()
                    res2 = ic.dropIntoSlot(sides.forward, x + (y - 1) * 9)
                end
        )
        return res2
    end
end
--[[
	循环放置1350eu核电散热片
 ]]
Utils.placeMultiNuclearFor1350EU = function(x_num, y_num)
    if require("component").inventory_controller == nil then
        return false, "no inventory_controller_upgrade"
    end
    local chv = "ic2:component_heat_vent"
    local ahv = "ic2:advanced_heat_vent"
    local che = "ic2:component_heat_exchanger"
    local res, msg = Utils.numCheck(
            {
                [chv] = x_num * y_num * 11,
                [ahv] = x_num * y_num * 27,
                [che] = x_num * y_num * 11
            }
    )
    if res == false then
        return res, msg
    end
    return Utils.doMultiNuclearThings(x_num, y_num, Utils.placeNuclearRadiatorFor1350EU)
end
--[[
	循环放置360eu核电散热片
 ]]
Utils.placeMultiNuclearFor360EU = function(x_num, y_num, need_plating)
    if require("component").inventory_controller == nil then
        return false, "no inventory_controller_upgrade"
    end
    if need_plating == nil then
        -- 默认会放置反应堆隔板 The reactor bulkhead will be placed by default
        need_plating = true
    end

    local ohv = "ic2:overclocked_heat_vent"
    local chv = "ic2:component_heat_vent"
    local plating = "ic2:plating"
    local res, msg = Utils.numCheck(
            {
                [ohv] = x_num * y_num * 24,
                [chv] = x_num * y_num * 12,
                [plating] = x_num * y_num * 12
            }
    )
    if res == false then
        return res, msg
    end
    return Utils.doMultiNuclearThings(x_num, y_num, Utils.placeNuclearRadiatorFor360EU, need_plating)
end
Utils.placeNuclearBlocks = function()
    local res, msg = Utils.numNameLabelCheck(
            {
                [{ "ic2:te", "Nuclear Reactor" }] = 1,
                [{ "ic2:te", "Reactor Chamber" }] = 6
            }
    )
    if res == false then
        return res, msg
    end
    local R = "Nuclear Reactor"
    local C = "Reactor Chamber"
    Utils.forward()
    Utils.placeAhead_S("ic2:te", false, R)
    Utils.down()
    Utils.placeAhead_S("ic2:te", false, C)
    Utils.up(2)
    Utils.placeDown_S("ic2:te", false, C)
    Utils.forward(2)
    Utils.placeDown_S("ic2:te", false, C)
    Utils.back()
    Utils.moveLeft(1)
    Utils.placeDown_S("ic2:te", false, C)
    Utils.moveRight(2)
    Utils.placeDown_S("ic2:te", false, C)
    Utils.moveLeft(1)
    Utils.back()
    Utils.placeAhead_S("ic2:te", false, C)
    Utils.back()
    Utils.down()
    return true
end
Utils.placeMultiNuclearBlocks = function(x_num, y_num)
    -- if require('component').inventory_controller == nil then
    -- 	return false, 'no inventory_controller_upgrade'
    -- end
    -- local temp = Utils.getTotalNumOf('ic2:te', 'Nuclear Reactor') - 1 * x_num * y_num
    -- if temp < 0 then
    -- 	return false, "still need " .. tostring(-temp) .. " Nuclear Reactor(s)"
    -- end
    -- temp = Utils.getTotalNumOf('ic2:te', 'Reactor Chamber') - 6 * x_num * y_num
    -- if temp < 0 then
    -- 	return false, "still need " .. tostring(-temp) .. " Reactor Chamber(s)"
    -- end
    -- local t1=
    local res, msg = Utils.numNameLabelCheck(
            {
                [{ "ic2:te", "Nuclear Reactor" }] = 1 * x_num * y_num,
                [{ "ic2:te", "Reactor Chamber" }] = 6 * x_num * y_num
            }
    )
    if res == false then
        return res, msg
    end
    return Utils.doMultiNuclearThings(x_num, y_num, Utils.placeNuclearBlocks)
end
Utils.heatMultiReactorTo85Degrees = function(x_num, y_num, secs)
    return Utils.doMultiNuclearThings(x_num, y_num, Utils.heatReactorTo85Degrees, secs)
end

Utils.heatReactorTo85Degrees = function(secs)
    if secs == nil then
        secs = 87
    end
    local ic = require("component").inventory_controller
    if ic == nil then
        return false, "no inventory_controller_upgrade"
    end
    local res, msg = Utils.numCheck(
            {
                ["ic2:quad_uranium_fuel_rod"] = 1
            }
    )
    if res == false then
        return res, msg
    end

    Utils.select(
            Utils.getSlotIdByItemName("ic2:quad_uranium_fuel_rod"),
            1,
            function()
                local res = ic.getStackInInternalSlot()
                local durability = res.maxDamage - res.damage
                if durability < 100 then
                    return false, "not enough durability for fuel rod"
                else
                    ic.dropIntoSlot(sides.forward, 1)
                    os.sleep(secs)
                    ic.suckFromSlot(sides.forward, 1)
                end
            end
    )
end

Utils.doMultiNuclearThings = function(x_num, y_num, func, ...)
    -- local args={...}
    for i = 1, y_num do
        for j = 1, x_num do
            func(...)
            if (j < x_num) then
                Utils.moveRight(3)
            end
        end
        Utils.moveLeft(3 * (x_num - 1))
        if (i < y_num) then
            Utils.up(3, true)
            -- Utils.placeDown_S('ic2:resource')
            Utils.up(1, true)
        end
    end
    Utils.down(4 * y_num - 4)
    return true
end
Utils.getInventoryController = function()
    return require("component").inventory_controller
end
Utils.numNameLabelCheck = function(namelabel_value_arr)
    if Utils.getInventoryController() == nil then
        return false, "no inventory controller upgrade"
    end
    local flag = true
    local message = ""
    for name_label, value in pairs(namelabel_value_arr) do
        local temp = value - Utils.getTotalNumOf(name_label[1], name_label[2])
        if temp > 0 then
            -- print('debug:')
            -- print('name:'..tostring(name)..' value:'..tostring(value)..' temp:'..tostring(temp))
            flag = false
            message = message .. "need " .. name_label[1] .. " labeled " .. name_label[2] .. " : " .. tostring(temp) .. "  "
        end
    end
    if flag == false then
        return false, message
    else
        return true
    end
end
Utils.numCheck = function(name_value_arr)
    if Utils.getInventoryController() == nil then
        return false, "no inventory controller upgrade"
    end
    local flag = true
    local message = ""
    for name, value in pairs(name_value_arr) do
        local temp = value - Utils.getTotalNumOf(name)
        if temp > 0 then
            -- print('debug:')
            -- print('name:'..tostring(name)..' value:'..tostring(value)..' temp:'..tostring(temp))
            flag = false
            message = message .. "need " .. name .. " : " .. tostring(temp) .. "  "
        end
    end
    if flag == false then
        return false, message
    else
        return true
    end
end
--[[
	为核电摆设线缆，放置拉杆并启动。在建好核电房、摆好反应堆以后可以进行这一步。
	注意机器人的初始位置是面向最左边的核反应堆，面前是一个核反应仓，核反应仓前面是核反应堆。
 ]]
Utils.placeCablesAndOpenedLeversForOneLayerNuclear = function(x_num)
    local ic2cable = "ic2:cable"
    local rscable = "refinedstorage:cable"
    local importer = "refinedstorage:importer"
    local exporter = "refinedstorage:exporter"
    local lever = "minecraft:lever"
    local res, msg = Utils.numCheck(
            {
                [ic2cable] = 3 * x_num,
                [rscable] = 3 * x_num - 1,
                [importer] = x_num,
                [exporter] = x_num,
                [lever] = x_num
            }
    )
    if not res then
        -- 如果因为一些原因导致错误，则返回错误的同时也把返回信息返回，而不是打印出来。
        return res, msg
    end
    -- 现在没有任何物品的缺少了，可以开始干活了。
    -- 先往左边的房子缺口放置线缆。如果房子没有缺口也没关系，放置不了而已。
    Utils.moveLeft()
    Utils.up()
    Utils.forward()
    Utils.turnLeft()
    Utils.placeAhead_S(rscable)
    Utils.down(2)
    Utils.placeAhead_S(ic2cable)
    Utils.up(2)
    Utils.turnRight()
    Utils.back()
    Utils.down()
    Utils.moveRight()
    -- 填补好缺口后，可以开始循环干活了
    for i = 1, x_num do
        if i < x_num then
            Utils.moveLeft()
            Utils.up()
            Utils.forward()
            Utils.placeAhead_S(importer, false, nil, sides.right)
            Utils.placeDown_S(exporter, false, nil, sides.right)
            Utils.back()
            Utils.placeAhead_S(rscable, false)
            Utils.moveRight()
            Utils.placeAhead_S(rscable, false)
            Utils.moveRight()
            Utils.placeAhead_S(rscable, false)
            Utils.down()
            Utils.placeAhead_S(lever, false, nil, sides.front)
            bot.use(sides.front)
            Utils.down()
            Utils.placeAhead_S(ic2cable, false)
            Utils.moveLeft()
            Utils.placeAhead_S(ic2cable, false)
            Utils.moveLeft()
            Utils.placeAhead_S(ic2cable, false)
            Utils.moveRight()
            Utils.up()

            Utils.moveRight(3)
        else
            -- 最右边少放两个rscable和一个ic2cable
            Utils.moveLeft()
            Utils.up()
            Utils.forward()
            Utils.placeAhead_S(importer, false, nil, sides.right)
            Utils.placeDown_S(exporter, false, nil, sides.right)
            Utils.back()
            Utils.placeAhead_S(rscable, false)
            Utils.moveRight()
            -- Utils.placeAhead_S(rscable,false)
            Utils.moveRight()
            -- Utils.placeAhead_S(rscable,false)
            Utils.down()
            Utils.placeAhead_S(lever, false, nil, sides.front)
            bot.use(sides.front)
            Utils.down()
            -- Utils.placeAhead_S(ic2cable,false)
            Utils.moveLeft()
            Utils.placeAhead_S(ic2cable, false)
            Utils.moveLeft()
            Utils.placeAhead_S(ic2cable, false)
            Utils.moveRight()
            Utils.up()
            Utils.moveLeft(3 * x_num - 3)
        end
    end
end
Utils.placeMultiCablesAndOpenedLeversForOneLayerNuclear = function(x_num, y_num)
    local ic2cable = "ic2:cable"
    local rscable = "refinedstorage:cable"
    local importer = "refinedstorage:importer"
    local exporter = "refinedstorage:exporter"
    local lever = "minecraft:lever"
    local res, msg = Utils.numCheck(
            {
                [ic2cable] = 3 * x_num * y_num,
                [rscable] = (3 * x_num - 1) * y_num,
                [importer] = x_num * y_num,
                [exporter] = x_num * y_num,
                [lever] = x_num * y_num
            }
    )
    if not res then
        -- 如果因为一些原因导致错误，则返回错误的同时也把返回信息返回，而不是打印出来。
        return res, msg
    end
    for i = 1, y_num do
        if i < y_num then
            Utils.placeCablesAndOpenedLeversForOneLayerNuclear(x_num)
            Utils.up(4, true)
        else
            Utils.placeCablesAndOpenedLeversForOneLayerNuclear(x_num)
            Utils.down(4 * y_num - 4, true)
        end
    end
end
Utils.buildClassicNuclearHouse = function(name, layers, opening, num_check)
    return Utils.buildNuclearHouse(name, 4 * 3 + 2, 3 + 3 + 2, 3 + 2, layers, opening, num_check)
end
Utils.directlyBuildClassicNuclearHouse = function(layers, opening, num_check)
    return Utils.directlyBuildNuclearHouse(4 * 3 + 2, 3 + 3 + 2, 3 + 2, layers, opening, num_check)
end
Utils.shuaFangBaoShi = function(num, tool_name)
    local ic = Utils.getInventoryController()
    if (ic == nil) then
        return "no inventory controller upgrade"
    end
    if tool_name == nil then
        tool_name = "ic2:iridium_drill"
    end
    local penqiang = "ic2:foam_sprayer"
    local shazi = "minecraft:sand"
    local jiaoshoujia = "ic2:scaffold"
    -- local res,msg=Utils.numCheck({[c]= 11,[a]= 27,[e]= 11})
    local res, msg = Utils.numCheck(
            {
                [shazi] = num,
                [jiaoshoujia] = num,
                [penqiang] = 1,
                [tool_name] = 1
            }
    )
    if res == false then
        return res, msg
    end
    for i = 1, num do
        -- 第一步，放铁脚手架
        Utils.placeAhead_S(jiaoshoujia)
        -- 第二步，装备喷枪
        Utils.select(Utils.getSlotIdByItemName(penqiang), 1, ic.equip)
        -- 第三步，填充喷枪
        bot.useUp()
        -- 第四步，使用喷枪
        bot.use()
        -- 第五步，装备沙子
        Utils.select(Utils.getSlotIdByItemName(shazi), 1, ic.equip)
        -- 第六步，使用沙子
        bot.use()
        -- 第七步，装备挖掘工具
        Utils.select(Utils.getSlotIdByItemName(tool_name), 1, ic.equip)
        -- 第八步，swing
        bot.swing()
    end
end
Utils.shuaFangBaoShiV2 = function(num, tool_name, interval)
    local ic = Utils.getInventoryController()
    if (ic == nil) then
        return "no inventory controller upgrade"
    end
    if tool_name == nil then
        tool_name = "ic2:iridium_drill"
    end
    if interval == nil then
        interval = 200
    end
    local penqiang = "ic2:foam_sprayer"
    local shazi = "minecraft:sand"
    local jiaoshoujia = "ic2:scaffold"
    local res, msg = Utils.numCheck(
            {
                -- [shazi] = num,
                -- [jiaoshoujia] = num,
                [penqiang] = 1,
                [tool_name] = 1
            }
    )
    if res == false then
        return res, msg
    end
    for i = 1, num do
        if i % interval == 1 then
            Utils.ForEachNotNilInternalInventory(function(slot, stack)
                if stack.name == 'ic2:resource' then
                    Utils.select(slot, 1, function()
                        bot.dropDown()
                    end)
                end
            end)

            local jiaoshoujia_num = Utils.getTotalNumOf(jiaoshoujia)

            if (jiaoshoujia_num < interval) then
                local res, msg = Utils.suckSpecifiedNumofItemsWithSide(sides.down, jiaoshoujia, interval)
                if res == false then
                    return res, msg
                end
            end
            local sand_num = Utils.getTotalNumOf(shazi)
            if (sand_num < interval) then
                local res, msg = Utils.suckSpecifiedNumofItemsWithSide(sides.down, shazi, interval)
                if res == false then
                    return res, msg
                end
            end
        end
        -- 第一步，放铁脚手架
        Utils.placeAhead_S(jiaoshoujia)
        -- 第二步，装备喷枪
        Utils.select(Utils.getSlotIdByItemName(penqiang), 1, ic.equip)
        -- 第三步，填充喷枪
        bot.useUp()
        -- 第四步，使用喷枪
        if bot.use() == false then
            bot.useUp()
            if bot.use() == false then
                return false, 'not enough building foam'
            end
        end
        -- 第五步，装备沙子
        Utils.select(Utils.getSlotIdByItemName(shazi), 1, ic.equip)
        -- 第六步，使用沙子
        bot.use()
        -- 第七步，装备挖掘工具
        Utils.select(Utils.getSlotIdByItemName(tool_name), 1, ic.equip)
        -- 第八步，swing
        bot.swing()
    end
    return true
end
Utils.regularlyPlaceAndSwing = function(blockName, num, numCheck)
    local ic = Utils.getInventoryController()
    if ic == nil then
        return "no inventory controller upgrade"
    end
    if numCheck == nil then
        numCheck = true
    end
    if numCheck then
        local res, msg = Utils.numCheck(
                {
                    [blockName] = num
                }
        )
        if res == false then
            return res, msg
        end
    end

    for i = 1, num do
        Utils.placeDown_S(blockName)
        bot.swingDown()
    end
    return true
end
Utils.getInventorysTotalNumOfWithSide = function(side, givenName, label)
    local ic = Utils.getInventoryController()
    if ic == nil then
        return nil, "no inventory controller upgrade"
    end
    local maxSize, msg = ic.getInventorySize(side)
    if maxSize == nil then
        return maxSize, msg
    end
    local sum = 0
    for i = 1, maxSize do
        local item = ic.getStackInSlot(side, i)
        if (item ~= nil) then
            local itemName = item.name
            if (itemName == givenName) then
                if label ~= nil then
                    if (item.label == label) then
                        sum = sum + item.size
                        -- ic.getSlotStackSize(side,i)
                    end
                else
                    sum = sum + item.size
                end
            end
        end
    end
    return sum
end
Utils.suckSpecifiedNumofItemsWithSide = function(side, givenName, need_num, label, wait)
    local ic = Utils.getInventoryController()
    if ic == nil then
        return false, "no inventory controller upgrade"
    end
    local inv_num, msg = Utils.getInventorysTotalNumOfWithSide(side, givenName, label)
    if inv_num == nil then
        return false, msg
    end
    if wait == nil then
        wait = false
    end
    if need_num > inv_num then
        if wait then
            while true do
                os.sleep(10)
                inv_num, msg = Utils.getInventorysTotalNumOfWithSide(side, givenName, label)
                if inv_num == nil then
                    return false, msg
                end
                if need_num <= inv_num then
                    break
                end
            end
        else
            return false, "still need " .. tostring(need_num - inv_num) .. " " .. givenName
        end
    end
    local still_need_num = need_num
    local maxSize = ic.getInventorySize(side)
    for i = 1, maxSize do
        local item = ic.getStackInSlot(side, i)
        if (item ~= nil) then
            local itemName = item.name
            local itemLabel = item.label
            if label == nil then
                itemLabel = nil
            end
            if (itemName == givenName and itemLabel == label) then
                if still_need_num > item.size then
                    still_need_num = still_need_num - item.size

                    ic.suckFromSlot(side, i, item.size)
                else
                    -- still_need_num = 0
                    ic.suckFromSlot(side, i, still_need_num)
                    break
                end
            end
        end
    end
    return true
end
--[[
    尝试从side方向的容器中获取物品至机器人的该物品总数为need_num个
 ]]
Utils.fillUp2SpecifiedNumofItemsWithSide = function(side, givenName, need_num, label, wait)
    local current_num = Utils.getTotalNumOf(givenName, label)
    local still_need_num = need_num - current_num
    if still_need_num <= 0 then
        --不需要补足，机器人已经有足够的物品。
        return true
    else
        --需要补足
        return Utils.suckSpecifiedNumofItemsWithSide(side, givenName, still_need_num, label, wait)
    end
end
Utils.Nuclear1stepFor1350EU = function(x_num, y_num, buildBlockNumCheck)
    local ic = Utils.getInventoryController()
    if ic == nil then
        return false, 'no_inventory_controller_upgrade'
    end
    if buildBlockNumCheck == nil then
        buildBlockNumCheck = true
    end
    local length = x_num * 3 + 2
    local width = 3 + 3 + 2
    local height = 3 + 2
    local resource_needed = width * length + y_num * (width * length + (height - 2) * (2 * (length + width) - 4))
    local res, msg
    if buildBlockNumCheck == false then
        res, msg = Utils.numCheck({ ['ic2:resource'] = resource_needed })
        if res == false then
            return res, msg
        end
    end

    res, msg = Utils.numCheck({ ['minecraft:diamond_pickaxe'] = 1 })
    if res == false then
        return res, msg
    end
    res, msg = Utils.numNameLabelCheck(
            {
                [{ "ic2:te", "Nuclear Reactor" }] = 1 * x_num * y_num,
                [{ "ic2:te", "Reactor Chamber" }] = 6 * x_num * y_num
            }
    )
    if res == false then
        return res, msg
    end
    local ic2cable = "ic2:cable"
    local rscable = "refinedstorage:cable"
    local importer = "refinedstorage:importer"
    local exporter = "refinedstorage:exporter"
    local lever = "minecraft:lever"
    res, msg = Utils.numCheck(
            {
                [ic2cable] = 3 * x_num * y_num,
                [rscable] = (3 * x_num - 1) * y_num,
                [importer] = x_num * y_num,
                [exporter] = x_num * y_num,
                [lever] = x_num * y_num
            }
    )
    if not res then
        -- 如果因为一些原因导致错误，则返回错误的同时也把返回信息返回，而不是打印出来。
        return res, msg
    end
    res, msg = Utils.numCheck(
            {
                ["ic2:quad_uranium_fuel_rod"] = 1
            }
    )
    if res == false then
        return res, msg
    end

    Utils.select(
            Utils.getSlotIdByItemName("ic2:quad_uranium_fuel_rod"),
            1,
            function()
                local res = ic.getStackInInternalSlot()
                local durability = res.maxDamage - res.damage
                if durability < 90 * x_num * y_num then
                    return false, "not enough durability for fuel rod"
                    -- else
                    -- ic.dropIntoSlot(sides.forward, 1)
                    -- os.sleep(secs)
                    -- ic.suckFromSlot(sides.forward, 1)
                end
            end
    ,
            true
    )

    --第一步，搭核电房
    Utils.directlyBuildNuclearHouse(length, width, height, y_num, true, false)
    --第二步，来到正确位置
    Utils.moveRight(2)
    Utils.forward(3)
    Utils.up()
    Utils.down(y_num * 4, true)
    --第三步，放置核反应堆和仓
    Utils.placeMultiNuclearBlocks(x_num, y_num)
    --第四步，放置线缆
    Utils.placeMultiCablesAndOpenedLeversForOneLayerNuclear(x_num, y_num)
    --第五步,控温
    Utils.heatMultiReactorTo85Degrees(x_num, y_num)

    print(
            'Heating Complete. Now you should set InputCable Mode to WHITELIST and connect All the cables and then prepare NuclearRadiators for me!')
    while true do
        print('press enter to continue')
        io.read()
        local chv = "ic2:component_heat_vent"
        local ahv = "ic2:advanced_heat_vent"
        local che = "ic2:component_heat_exchanger"
        res, msg = Utils.numCheck(
                {
                    [chv] = x_num * y_num * 11,
                    [ahv] = x_num * y_num * 27,
                    [che] = x_num * y_num * 11
                }
        )
        if res == false then
            print(msg)
        else
            break
        end
    end
    Utils.placeMultiNuclearFor1350EU(x_num, y_num)
    return true
end
Utils.ForEachNotNilInternalInventory = function(func)
    local size = bot.inventorySize()
    local ic = require("component").inventory_controller
    if (ic == nil) then
        -- ??????????????????????????????
        return false, "no inventory_controller upgrade"
    end
    for i = 1, size do
        local stack = ic.getStackInInternalSlot(i)
        if (stack ~= nil) then
            func(i, stack)
        end
    end
    return true
end
Utils.ForEachInternalInventory = function(func)
    local size = bot.inventorySize()
    local ic = require("component").inventory_controller
    if (ic == nil) then
        -- ??????????????????????????????
        return false, "no inventory_controller upgrade"
    end
    for i = 1, size do
        local stack = ic.getStackInInternalSlot(i)
        -- if (stack ~= nil) then
        func(i, stack)
        -- end
    end
    return true
end
-- Utils.placeFloor
Utils.placeOneFloor32EU = function(length, width, numCheck)
    local ic = Utils.getInventoryController()
    if ic == nil then
        return false, 'no inventory_controller'
    end
    if numCheck == nil then
        numCheck = true
    end
    local te = "Radioisotope Thermoelectric Generator"
    local nu = "Pellets of RTG Fuel"
    local ca = "Glass Fibre Cable"
    if numCheck then
        local res, msg = Utils.numNameLabelCheck(
                {
                    [{ "ic2:te", te }] = 2 * length * width,
                    [{ "ic2:nuclear", nu }] = 12 * length * width,
                    [{ "ic2:cable", ca }] = 1 * length * width
                }
        )
        if res == false then
            return res, msg
        end
    end

    Utils.up()
    for i = 1, length do
        for j = 1, width do
            Utils.placeDown_S("ic2:te", false, te)
            for k = 2, 7 do
                Utils.select(Utils.getSlotIdByItemName("ic2:nuclear", nu), 1, function()
                    ic.dropIntoSlot(sides.bottom, k, 1)
                end, true)
            end

            if j < width then
                Utils.forward()
            end
        end
        Utils.back(width - 1)
        if i < length then
            Utils.moveRight()
        end
    end
    Utils.moveLeft(length - 1)

    Utils.up()
    for i = 1, length do
        for j = 1, width do
            Utils.placeDown_S("ic2:cable", false, ca)
            if j < width then
                Utils.forward()
            end
        end
        Utils.back(width - 1)
        if i < length then
            Utils.moveRight()
        end
    end
    Utils.moveLeft(length - 1)

    Utils.up()
    for i = 1, length do
        for j = 1, width do
            Utils.placeDown_S("ic2:te", false, te)
            for k = 2, 7 do
                Utils.select(Utils.getSlotIdByItemName("ic2:nuclear", nu), 1, function()
                    ic.dropIntoSlot(sides.bottom, k, 1)
                end, true)
            end

            if j < width then
                Utils.forward()
            end
        end
        Utils.back(width - 1)
        if i < length then
            Utils.moveRight()
        end
    end
    Utils.moveLeft(length - 1)
    return true
end
Utils.placeMultiFloor32EU = function(length, width, layers, numCheck)
    local ic = Utils.getInventoryController()
    if ic == nil then
        return false, 'no inventory_controller'
    end
    if numCheck == nil then
        numCheck = true
    end
    local te = "Radioisotope Thermoelectric Generator"
    local nu = "Pellets of RTG Fuel"
    local ca = "Glass Fibre Cable"
    if numCheck then
        local res, msg = Utils.numNameLabelCheck(
                {
                    [{ "ic2:te", te }] = 2 * length * width * layers,
                    [{ "ic2:nuclear", nu }] = 12 * length * width * layers,
                    [{ "ic2:cable", ca }] = 1 * length * width * layers
                }
        )
        if res == false then
            return res, msg
        end
    end

    for i = 1, layers do
        Utils.placeOneFloor32EU(length, width, false)
    end
    return true
end
--[[
    获取机器人空的背包格子数
 ]]
Utils.getEmptyInternalSlotNumber = function()
    local sum = 0
    Utils.ForEachInternalInventory(function(i, stack)
        if stack == nil then
            sum = sum + 1
        end
    end)
    return sum;
end
--[[
    由于靶丸发电需要的物品数量过多，一次性难以将多层的靶丸发电厂完全做好，下面的这个函数在每层发电厂搭建之前，都会检查三种物品是否足够建好这一层。
    如果材料不够，后退一格后来到第一层（即机器人最开始所在高度的背后一格），在这一格的背后备有靶丸，左边备有发电机，右边备有玻璃纤维导线。机器人先查看背包的空余空间。之后按比例12:2:1填充空余空间。
    填充后，回到之前所在层进行工作。
 ]]
Utils.placeMultiFloor32EUAutoFillBackPack = function(length, width, layers)
    local ic = Utils.getInventoryController()
    if ic == nil then
        return false, 'no inventory_controller'
    end
    local te = "Radioisotope Thermoelectric Generator"
    local nu = "Pellets of RTG Fuel"
    local ca = "Glass Fibre Cable"
    -- if numCheck then
    --     local res, msg =
    --     Utils.numNameLabelCheck(
    --         {
    --             [{ "ic2:te", te }] = 2 * length * width * layers,
    --             [{ "ic2:nuclear", nu }] = 12 * length * width * layers,
    --             [{ "ic2:cable", ca }] = 1 * length * width * layers
    --         }
    --     )
    --     if res == false then
    --         return res, msg
    --     end
    -- end

    for i = 1, layers do
        local res, msg = Utils.numNameLabelCheck(
                {
                    [{ "ic2:te", te }] = 2 * length * width,
                    [{ "ic2:nuclear", nu }] = 12 * length * width,
                    [{ "ic2:cable", ca }] = 1 * length * width
                }
        )
        if res == false then
            --机器人背包的材料已经不足以搭建这一层了
            local res2, msg2
            Utils.back()
            Utils.down(3 * (i - 1))
            local emptySlotNumber = Utils.getEmptyInternalSlotNumber() --空格子数*64
            local numof15M64 = math.floor(emptySlotNumber / 15)        --空格子数地板除以15
            Utils.turnLeft()
            while true do
                res2, msg2 = Utils.suckSpecifiedNumofItemsWithSide(sides.forward, 'ic2:te', numof15M64 * 64 * 2, te)
                if res2 == true then
                    break
                end
                os.sleep(10)
                print(msg)
            end

            Utils.turnLeft()
            while true do
                res2, msg2 = Utils.suckSpecifiedNumofItemsWithSide(sides.forward, 'ic2:nuclear', numof15M64 * 64 * 12, nu)
                if res2 == true then
                    break
                end
                os.sleep(10)
                print(msg)
            end

            Utils.turnLeft()
            while true do
                res2, msg2 = Utils.suckSpecifiedNumofItemsWithSide(sides.forward, 'ic2:cable', numof15M64 * 64 * 1, ca)
                if res2 == true then
                    break
                end
                os.sleep(10)
                print(msg)
            end

            Utils.turnLeft()
            Utils.up(3 * (i - 1))
            Utils.forward()
        end

        Utils.placeOneFloor32EU(length, width, false)
    end
    return true
end
--[[
    将机器人背包中所有满足条件的物品放入指定方向的箱子中。
 ]]
Utils.dropAll = function(name, label)
    Utils.ForEachNotNilInternalInventory(function(slot, stack)
        local stackLabel = stack.label
        if label == nil then
            stackLabel = nil
        end
        if stack.name == name and stackLabel == label then
            Utils.select(slot, 1, function()
                bot.drop()
            end, true)
        end
    end)
end
--[[
    将机器人背包中所有满足条件的物品放入指定方向的箱子中。
 ]]
Utils.dropDownAll = function(name, label)
    Utils.ForEachNotNilInternalInventory(function(slot, stack)
        local stackLabel = stack.label
        if label == nil then
            stackLabel = nil
        end
        if stack.name == name and stackLabel == label then
            Utils.select(slot, 1, function()
                bot.dropDown()
            end, true)
        end
    end)
end

--[[
    将机器人背包中所有满足条件的物品放入上方的箱子中。
 ]]
Utils.dropUpAll = function(name, label)
    Utils.ForEachNotNilInternalInventory(function(slot, stack)
        local stackLabel = stack.label
        if label == nil then
            stackLabel = nil
        end
        if stack.name == name and stackLabel == label then
            Utils.select(slot, 1, function()
                bot.dropUp()
            end, true)
        end
    end)
end

--[[ 注：实际检验后发此函数不能全自动产荧石，原因是对一个村民只使用三种交易不能保证货物刷新
    当玩家需要无限获得萤石的时候，可以使用这个函数
    事先机器人左，前，右分别是装有小麦，胡萝卜，马铃薯的箱子。
    这个函数让机器人使用自己的背包的东西购买绿宝石。
    同时每当背包绿宝石数大于等于buffered_emerald_num时，将自身背包的绿宝石优先换荧石，没有荧石时但有绿宝石时，优先换青金石，没有青金石、荧石但有绿宝石时，最后换红石，如此反复直到绿宝石用尽。
    此时机器人会将所有的荧石、青金石、红石放入头顶上的容器中
 ]]
Utils.buyEmeraldUsingEverythingAndBuyRBY = function(crops_num, buffered_emerald_num)
    local wheat = 'minecraft:wheat'
    local carrot = 'minecraft:carrot'
    local potato = 'minecraft:potato'
    local emerald = 'minecraft:emerald'
    if crops_num == nil then
        crops_num = 64
    end
    if buffered_emerald_num == nil then
        buffered_emerald_num = 10
    end
    --每次交易之后都要查看交易是否成功，交易失败才去进行个数检查
    --个数检查，机器人检查小麦、胡萝卜、马铃薯的个数时否足够。
    --采用放缩法，单个农作物个数小于64个时，认为该农作物不够。
    --三种农作物有一种不够时，将三种都补全至每种crops_num个,补全时出现无法补全情况时，原地等待10秒，再补全，如此反复。
    --每次交易之后并检查交易是否成功后，检查绿宝石的量。

    while true do
        local res = Utils.Buy(nil, "minecraft:emerald", 1, false)
        if res == false then
            --要么就是没有购买绿宝石的交易了，要么就是机器人的材料不够了。
            --由于交易涉及到一个村民的三种商品，因此不可能没有购买绿宝石的交易，只可能是机器人的农作物不够。
            --此时将三种农作物都补全至每咱crops_num个
            Utils.turnLeft()
            Utils.fillUp2SpecifiedNumofItemsWithSide(sides.forward, wheat, crops_num, nil, true)
            Utils.turnRight()
            Utils.fillUp2SpecifiedNumofItemsWithSide(sides.forward, carrot, crops_num, nil, true)
            Utils.turnRight()
            Utils.fillUp2SpecifiedNumofItemsWithSide(sides.forward, potato, crops_num, nil, true)
            Utils.turnLeft()
        end
        if Utils.getTotalNumOf(emerald) >= buffered_emerald_num then
            --暂存的绿宝石个数到达上限，开始用绿宝石进行购买
            --若绿宝石个数大于等于buffered_emerald_num，将自身背包的绿宝石优先换荧石，没有荧石时但有绿宝石时，优先换青金石，没有青金石、荧石但有绿宝石时，最后换红石，如此反复直到绿宝石用尽。

            while Utils.getTotalNumOf(emerald) > 0 do
                local res = Utils.BuySpecifiedThingUsingEmerald('minecraft:glowstone', 1, false)
                if res == false then
                    res = Utils.BuySpecifiedThingUsingEmerald('minecraft:dye', 1, false)
                    if res == false then
                        res = Utils.BuySpecifiedThingUsingEmerald('minecraft:redstone', 1, false)
                        if res == false then
                            return false, 'sth unexpected occurred!'
                        end
                    end
                end
            end
            --此时机器人会将所有的荧石、青金石、红石放入头顶上的容器中
            Utils.dropUpAll('minecraft:glowstone')
            Utils.dropUpAll('minecraft:dye')
            Utils.dropUpAll('minecraft:redstone')
        end
    end
end
--[[
    回调函数参数 i:slotId, stack:stack数据
 ]]
Utils.forEachInventory = function(side, func)
    local ic = require("component").inventory_controller
    if (ic == nil) then
        -- ??????????????????????????????
        return false, "no inventory_controller upgrade"
    end
    local size = ic.getInventorySize()
    for i = 1, size do
        local stack = ic.getStackInSlot(side, i)

        func(i, stack)
    end
    return true
end
--[[ 返回side向的第一个非空slot_id
 -1 :没有inventory_controller upgrade
 0 :全为空格子
 正数：第一个非空格子
]]
Utils.getFirstNotNilSlotId = function(side)
    local ic = require("component").inventory_controller
    if (ic == nil) then
        -- ??????????????????????????????
        return -1
    end
    local size = ic.getInventorySize(side)
    for i = 1, size do
        local stack = ic.getStackInSlot(side, i)
        if stack ~= nil then
            return i
        end
    end
    return 0
end
Utils.cut_arr_first = function(a)
    if #a == 0 then
        return nil
    end
    local b = {}
    -- local timer=1
    for k, v in ipairs(a) do
        if k ~= 1 then
            table.insert(b, v)
        end
        -- timer=timer+1
    end
    return b
end
--[[
    进行一次交易，在所有交易中优先选择列表靠前的物品进行绿宝石的购买。
 ]]
Utils.BuyEmeraldWithAdv = function(arr)
    if #arr == 0 then
        return false, 'all trades are disabled'
    end
    -- local arr = ...
    local res, msg = Utils.Buyv2(arr[1], 'minecraft:emerald')
    if res == true then
        return true
    elseif msg == 'not enough items to trade' then
        -- 机器人该种物品不够
        return false, 'not enough items to trade' --最多的物品不够，则停止并返回false
    else
        --交易无货
        return Utils.BuyEmeraldWithAdv(Utils.cut_arr_first(arr))
    end
end
--[[
    进行一次交易，在所有交易中优先选择列表靠前的物品进行物品的购买（使用绿宝石）。
 ]]
Utils.BuySthUsingEmeraldWithAdv = function(arr)
    if #arr == 0 then
        return false, 'all trades are disabled' --交易无货
    end
    -- local arr = ...
    local res, msg = Utils.Buyv2('minecraft:emerald', arr[1])
    if res == true then
        return true
    elseif msg == 'not enough items to trade' then
        -- 机器人该种物品不够
        return false, 'not enough items to trade' --绿宝石不够，则停止并返回false
    else
        return Utils.BuySthUsingEmeraldWithAdv(Utils.cut_arr_first(arr))
    end
end
--[[
    反复调用一个函数。
    参数：
    sleepTime:反复调用的间隔时间
    func:要调用的函数
    ...:要调用的函数的参数

 ]]
Utils.loopDo = function(sleepTime, func, ...)
    while true do
        func(...)
        os.sleep(sleepTime)
    end
end

--[[
    去牧师村民那购买红石，萤石，或青金石，三者对应a,b,c三个参数，参数越大购买优先级越高
    由于仅仅三种交易很容易让交易缺货，增加交易类型可以减小让交易缺货的频率。
    因此这个函数在红石，萤石，或青金石都售完后会尝试进行其它交易。（只允许机器人周围有一个牧师村民）
    从水平方向得到的视图如下：
    容器（金锭）            y=3            (指定需要金锭交易后，需要此层。)
    机器人                 y=2
    容器（输入到仓库）      y=1

    另外，机器人前方也有一个容器，存放着绿宝石
    俯视图如下：
    容器（绿宝石）（与机器人高度相同）
    机器人（机器人头顶可能有装金锭的容器）

    参数：
    a,b,c：红石，萤石，青金石分别对应这三个值，值大优先级高。
    need_gold_trade： 是否进行金锭交易以刷新村民备货
    need_other_2_trade:是否进行末影珍珠交易和附魔之瓶交易

 ]]
-- Utils.buyRedstoneGlowstoneAndBlueDyeWithAdv = function(a, b, c, need_gold_trade, need_other_2_trade, gold_first)
--     if gold_first == nil then --当need_gold_trade, need_other_2_trade同时为true时，gold trade是否优先
--         gold_first = true
--     end
--     if need_gold_trade == nil then
--         need_gold_trade = false --默认不进行金锭的消耗
--     end
--     if need_other_2_trade == nil then
--         need_other_2_trade = false --默认不进行末影珍珠交易和附魔之瓶交易
--     end
--     local goldIngotFillUpNum = 2 * 64
--     local emeraldFillUpNum = 4 * 64
--     local i = 1
--     while true do
--         --[[
--             进行优先级交易
--          ]]
--         local arr = { { name = 'minecraft:redstone', num = a }, { name = 'minecraft:glowstone', num = b },
--             { name = 'minecraft:dye',      num = c } }
--         -- local map={['minecraft:redstone']=a,['minecraft:glowstone']=b,['minecraft:dye']=c}
--         table.sort(arr, function(a1, b1)
--             return a1['num'] > b1['num']
--         end)
--         local fnarr = {}
--         for k, v in pairs(arr) do
--             table.insert(fnarr, v['name'])
--         end
--         --这里可能会出现三种情况
--         --[[
--             1.成功购买
--             2.由于机器人自已物品不够而无法购买
--             3.由于村民上述物品全部缺货而无法购买

--             1.成功购买
--                 无需进行后续操作，算作购买一次
--             2.由于机器人自已物品不够而无法购买
--                 机器人将去补货
--             3.由于村民上述物品全部缺货而无法购买
--                 进行后续的判断
--          ]]
--         local res, msg = Utils.BuySthUsingEmeraldWithAdv(fnarr)
--         if res == false then
--             if msg == 'all trades are disabled' then --由于村民上述物品全部缺货而无法购买
--                 if need_gold_trade == false and need_other_2_trade == false then
--                     return false, 'all trades are disabled'
--                 elseif need_gold_trade == true and need_other_2_trade == true then
--                     if gold_first then
--                         local res1, msg1 = Utils.BuyEmeraldWithAdv({ 'minecraft:gold_ingot' })
--                         if res1 == false then
--                             if msg1 == 'all trades are disabled' then
--                                 local res2, msg2 = Utils.BuySthUsingEmeraldWithAdv({ 'minecraft:ender_pearl',
--                                     'minecraft:experience_bottle' })
--                                 if res2 == false then
--                                     if msg2 == 'all trades are disabled' then
--                                         return false, 'all trades are disabled1'
--                                     else --由于机器人自已物品不够而无法购买
--                                         Utils.fillUp2SpecifiedNumofItemsWithSide(sides.forward, "minecraft:emerald",
--                                             emeraldFillUpNum)
--                                     end
--                                 end
--                             else --由于机器人自已物品不够而无法购买
--                                 Utils.fillUp2SpecifiedNumofItemsWithSide(sides.up, "minecraft:gold_ingot",
--                                     goldIngotFillUpNum)
--                             end
--                         end
--                     else
--                         local res1, msg1 = Utils.BuySthUsingEmeraldWithAdv({ 'minecraft:ender_pearl',
--                             'minecraft:experience_bottle' })
--                         if res1 == false then
--                             if msg1 == 'all trades are disabled' then
--                                 local res2, msg2 = Utils.BuyEmeraldWithAdv({ 'minecraft:gold_ingot' })
--                                 if res2 == false then
--                                     if msg2 == 'all trades are disabled' then
--                                         return false, 'all trades are disabled2'
--                                     else --由于机器人自已物品不够而无法购买
--                                         Utils.fillUp2SpecifiedNumofItemsWithSide(sides.up, "minecraft:gold_ingot",
--                                             goldIngotFillUpNum)
--                                     end
--                                 end
--                             else --由于机器人自已物品不够而无法购买
--                                 Utils.fillUp2SpecifiedNumofItemsWithSide(sides.forward, "minecraft:emerald",
--                                     emeraldFillUpNum)
--                             end
--                         end
--                     end
--                 elseif need_gold_trade == true and need_other_2_trade == false then
--                     local res1, msg1 = Utils.BuyEmeraldWithAdv({ 'minecraft:gold_ingot' })
--                     if res1 == false then
--                         if msg1 == 'all trades are disabled' then
--                             return false, 'all trades are disabled3'
--                         else --由于机器人自已物品不够而无法购买
--                             Utils.fillUp2SpecifiedNumofItemsWithSide(sides.up, "minecraft:gold_ingot",
--                                 goldIngotFillUpNum)
--                         end
--                     end
--                 elseif need_gold_trade == false and need_other_2_trade == true then
--                     local res2, msg2 = Utils.BuySthUsingEmeraldWithAdv({ 'minecraft:ender_pearl',
--                         'minecraft:experience_bottle' })
--                     if res2 == false then
--                         if msg2 == 'all trades are disabled' then
--                             return false, 'all trades are disabled4'
--                         else --由于机器人自已物品不够而无法购买
--                             Utils.fillUp2SpecifiedNumofItemsWithSide(sides.forward, "minecraft:emerald",
--                                 emeraldFillUpNum)
--                         end
--                     end
--                 end
--             else --由于机器人自已物品不够而无法购买
--                 Utils.fillUp2SpecifiedNumofItemsWithSide(sides.forward, "minecraft:emerald", emeraldFillUpNum)
--             end
--         end
--         i = i + 1
--         if i % 10 == 0 then
--             --交易之后，将得到的东西放入下面的容器中。
--             Utils.dropDownAll('minecraft:ender_pearl')
--             Utils.dropDownAll('minecraft:dye')
--             Utils.dropDownAll('minecraft:experience_bottle')
--             Utils.dropDownAll('minecraft:redstone')
--             Utils.dropDownAll('minecraft:glowstone')
--         end



--         -- --[[
--         --     第二步
--         --     检查物品的数量，不足则补足
--         --  ]]
--         -- if Utils.numCheck({ ["minecraft:emerald"] = emeraldFillUpNum }) == false then
--         --     Utils.fillUp2SpecifiedNumofItemsWithSide(sides.forward, "minecraft:emerald", emeraldFillUpNum)
--         -- end
--         -- if need_gold_trade then
--         --     if Utils.numCheck({ ["minecraft:gold_ingot"] = 64 * 2 }) == false then
--         --         Utils.fillUp2SpecifiedNumofItemsWithSide(sides.up, "minecraft:gold_ingot", 64 * 2)
--         --     end
--         -- end
--     end
--     -- local arr={{name='minecraft:redstone',num=a},{name='minecraft:glowstone',num=b},{name='minecraft:dye',num=c}}
--     -- -- local map={['minecraft:redstone']=a,['minecraft:glowstone']=b,['minecraft:dye']=c}
--     -- table.sort(arr, function(a1, b1)
--     --     return a1['num'] > b1['num']
--     -- end)
--     -- local fnarr={}
--     -- for k,v in pairs(arr) do
--     --     table.insert(fnarr,v['name'])
--     -- end
--     -- local res,msg=Utils.BuySthUsingEmeraldWithAdv(fnarr)
-- end
Utils.buyRedstoneGlowstoneAndBlueDyeWithAdv = function(a, b, c)
    local i = 1
    local arr = {
        { name = 'minecraft:redstone', num = a },
        { name = 'minecraft:glowstone', num = b },
        { name = 'minecraft:dye', num = c }
    }
    -- local map={['minecraft:redstone']=a,['minecraft:glowstone']=b,['minecraft:dye']=c}
    table.sort(arr, function(a1, b1)
        return a1['num'] > b1['num']
    end)
    local fnarr = {}
    for k, v in pairs(arr) do
        table.insert(fnarr, v['name'])
    end

    while true do
        --[[
            进行优先级交易
         ]]
        --准备一个购买数组
        local adv_arr = {
            { lose = 'minecraft:emerald', get = fnarr[1] },
            { lose = 'minecraft:emerald', get = fnarr[2] },
            { lose = 'minecraft:emerald', get = fnarr[3] },
            { lose = 'minecraft:rotten_flesh', get = 'minecraft:emerald' },
            { lose = 'minecraft:emerald', get = 'minecraft:ender_pearl' },
            { lose = 'minecraft:emerald', get = 'minecraft:experience_bottle' },
            { lose = 'minecraft:gold_ingot', get = 'minecraft:emerald' }
        }
        local res, msg = Utils.buyWithAdv(adv_arr, sides.forward, true)
        if res == false then
            return res, msg
        end
        i = i + 1
        if i % 10 == 0 then
            --交易之后，将得到的东西放入下面的容器中。
            Utils.dropAll('minecraft:ender_pearl')
            Utils.dropAll('minecraft:dye')
            Utils.dropAll('minecraft:experience_bottle')
            Utils.dropAll('minecraft:redstone')
            Utils.dropAll('minecraft:glowstone')
        end
    end
end
--[[
    使用5种作物进行绿宝石交换。Version 2，使用新函数，代码更简洁，占地面积也更小
    机器人前方需要有一个箱子。
 ]]
Utils.buyEmeraldUsing5CropsTypeV2 = function()
    local wheat = 'minecraft:wheat'
    local carrot = 'minecraft:carrot'
    local potato = 'minecraft:potato'
    local pumpkin = 'minecraft:pumpkin'
    local melon = 'minecraft:melon_block'
    local emerald = 'minecraft:emerald'
    -- local adv_arr = { pumpkin, melon, potato, wheat, carrot }
    local adv_Goods_to_be_purchased_due_to_replenishment = { 'minecraft:bread', 'minecraft:pumpkin_pie',
                                                             'minecraft:apple', 'minecraft:cookie', 'minecraft:cake' }
    local i = -1
    local adv_map = { { name = wheat, num = 100 }, { name = carrot, num = 100 }, { name = potato, num = 100 },
                      { name = pumpkin, num = 100 }, { name = melon, num = 100 } }
    while true do
        --[[
            进行优先级交易
         ]]
        --准备一个购买数组
        i = i + 1
        if i % 32 == 0 then
            --每买10次进行一次仓库物品数量的数据更新，从而排序
            adv_map = {}
            table.insert(adv_map, { name = wheat, num = Utils.tunnelSend_getItemCountByName(wheat) })
            table.insert(adv_map, { name = carrot, num = Utils.tunnelSend_getItemCountByName(carrot) })
            table.insert(adv_map, { name = potato, num = Utils.tunnelSend_getItemCountByName(potato) })
            table.insert(adv_map, { name = pumpkin, num = Utils.tunnelSend_getItemCountByName(pumpkin) })
            table.insert(adv_map, { name = melon, num = Utils.tunnelSend_getItemCountByName(melon) })
            table.sort(adv_map, function(a, b)
                return a['num'] > b['num']
            end)
            Utils.dropAll(adv_Goods_to_be_purchased_due_to_replenishment[1])
            Utils.dropAll(adv_Goods_to_be_purchased_due_to_replenishment[2])
            Utils.dropAll(adv_Goods_to_be_purchased_due_to_replenishment[3])
            Utils.dropAll(adv_Goods_to_be_purchased_due_to_replenishment[4])
            Utils.dropAll(adv_Goods_to_be_purchased_due_to_replenishment[5])
            Utils.dropAll(emerald)
        end

        local adv_arr = {
            { lose = adv_map[1]['name'], get = emerald, replenish_groups_num = 4 },
            { lose = adv_map[2]['name'], get = emerald, replenish_groups_num = 4 },
            { lose = adv_map[3]['name'], get = emerald, replenish_groups_num = 4 },
            { lose = adv_map[4]['name'], get = emerald, replenish_groups_num = 4 },
            { lose = adv_map[5]['name'], get = emerald, replenish_groups_num = 4 },
            { lose = emerald, get = adv_Goods_to_be_purchased_due_to_replenishment[1] },
            { lose = emerald, get = adv_Goods_to_be_purchased_due_to_replenishment[2] },
            { lose = emerald, get = adv_Goods_to_be_purchased_due_to_replenishment[3] },
            { lose = emerald, get = adv_Goods_to_be_purchased_due_to_replenishment[4] },
            { lose = emerald, get = adv_Goods_to_be_purchased_due_to_replenishment[5] }

        }
        local res, msg = Utils.buyWithAdv(adv_arr, sides.forward, true)
        if res == false then
            return res, msg
        end
    end
end
--[[
    使用5种作物进行绿宝石交换。
    平面图如下:
                作物1
    作物2       机器人      作物3
    作物4       空气        作物5
    另外，机器人上方放有接收绿宝石的容器 机器人面向作物1 5种作物没有位置要求，分别是小麦、马铃薯、胡萝卜、西瓜、南瓜
 ]]
Utils.buyEmeraldUsing5CropsType = function(crops_num, buffered_emerald_num)
    local ic = Utils.getInventoryController()
    if ic == nil then
        return false, 'no_inventory_controller_upgrade'
    end
    local wheat = 'minecraft:wheat'
    local carrot = 'minecraft:carrot'
    local potato = 'minecraft:potato'
    local pumpkin = 'minecraft:pumpkin'
    local melon = 'minecraft:melon_block'
    local emerald = 'minecraft:emerald'
    local adv_arr = { pumpkin, melon, potato, wheat, carrot }
    local adv_Goods_to_be_purchased_due_to_replenishment = { 'minecraft:bread', 'minecraft:pumpkin_pie',
                                                             'minecraft:apple', 'minecraft:cookie' }
    if crops_num == nil then
        crops_num = 64 * 2
    end
    if buffered_emerald_num == nil then
        buffered_emerald_num = 10
    end
    --每次交易之后都要查看交易是否成功，交易失败才去进行个数检查
    --个数检查，机器人检查小麦、胡萝卜、马铃薯的个数时否足够。
    --五种农作物有一种不够时，将五种都补全至每种crops_num个,补全时出现无法补全情况时，原地等待10秒，再补全，如此反复。
    --每次交易之后并检查交易是否成功后，检查绿宝石的量。

    while true do
        local res, msg = Utils.BuyEmeraldWithAdv(adv_arr)
        if res == false then
            --要么就是没有购买绿宝石的交易了，要么就是机器人的材料不够了。
            if msg == 'all trades are disabled' then
                --没有购买绿宝石的交易了
                Utils.fillUp2SpecifiedNumofItemsWithSide(sides.up, 'minecraft:emerald', 10, nil, true)
                local resx, msgx = Utils.BuySthUsingEmeraldWithAdv(adv_Goods_to_be_purchased_due_to_replenishment)
                if resx == false then
                    return resx, msgx
                end
                for i, v in ipairs(adv_Goods_to_be_purchased_due_to_replenishment) do
                    Utils.dropUpAll(v)
                end
                os.sleep(3)
            else
                --此时将五种农作物都补全至crops_num个
                local stack
                local cropname
                local id
                local tdarray = {}
                Utils.turnLeft()
                id = Utils.getFirstNotNilSlotId(sides.forward)
                if id > 0 then
                    stack = ic.getStackInSlot(sides.forward, id)
                    cropname = stack.name
                    Utils.fillUp2SpecifiedNumofItemsWithSide(sides.forward, cropname, crops_num, nil)
                    table.insert(tdarray, { name = cropname, num = Utils.tunnelSend_getItemCountByName(cropname) })
                end
                Utils.turnRight()
                id = Utils.getFirstNotNilSlotId(sides.forward)
                if id > 0 then
                    stack = ic.getStackInSlot(sides.forward, id)
                    cropname = stack.name
                    Utils.fillUp2SpecifiedNumofItemsWithSide(sides.forward, cropname, crops_num, nil)
                    table.insert(tdarray, { name = cropname, num = Utils.tunnelSend_getItemCountByName(cropname) })
                end
                Utils.turnRight()
                id = Utils.getFirstNotNilSlotId(sides.forward)
                if id > 0 then
                    stack = ic.getStackInSlot(sides.forward, id)
                    cropname = stack.name
                    Utils.fillUp2SpecifiedNumofItemsWithSide(sides.forward, cropname, crops_num, nil)
                    table.insert(tdarray, { name = cropname, num = Utils.tunnelSend_getItemCountByName(cropname) })
                end
                Utils.moveRight()
                id = Utils.getFirstNotNilSlotId(sides.forward)
                if id > 0 then
                    stack = ic.getStackInSlot(sides.forward, id)
                    cropname = stack.name
                    Utils.fillUp2SpecifiedNumofItemsWithSide(sides.forward, cropname, crops_num, nil)
                    table.insert(tdarray, { name = cropname, num = Utils.tunnelSend_getItemCountByName(cropname) })
                end
                Utils.turnAround()
                id = Utils.getFirstNotNilSlotId(sides.forward)
                if id > 0 then
                    stack = ic.getStackInSlot(sides.forward, id)
                    cropname = stack.name
                    Utils.fillUp2SpecifiedNumofItemsWithSide(sides.forward, cropname, crops_num, nil)
                    table.insert(tdarray, { name = cropname, num = Utils.tunnelSend_getItemCountByName(cropname) })
                end
                table.sort(tdarray, function(a, b)
                    return a['num'] > b['num']
                end)
                for i, v in ipairs(tdarray) do
                    adv_arr[i] = tdarray[i]['name']
                    print(tostring(i) .. ':' .. adv_arr[i])
                end
                Utils.turnRight()
                Utils.forward()
            end
        end
        if Utils.getTotalNumOf(emerald) >= buffered_emerald_num then
            --暂存的绿宝石个数到达上限
            --若绿宝石个数大于等于buffered_emerald_num，将自身背包的绿宝石优先换荧石，没有荧石时但有绿宝石时，优先换青金石，没有青金石、荧石但有绿宝石时，最后换红石，如此反复直到绿宝石用尽。

            -- while Utils.getTotalNumOf(emerald)>0 do
            --     local res=Utils.BuySpecifiedThingUsingEmerald('minecraft:glowstone',1,false)
            --     if res==false then
            --         res=Utils.BuySpecifiedThingUsingEmerald('minecraft:dye',1,false)
            --         if res==false then
            --             res=Utils.BuySpecifiedThingUsingEmerald('minecraft:redstone',1,false)
            --             if res==false then
            --                 return false,'sth unexpected occurred!'
            --             end
            --         end
            --     end
            -- end
            --此时机器人会将所有的荧石、青金石、红石放入头顶上的容器中
            -- Utils.dropUpAll('minecraft:glowstone')
            -- Utils.dropUpAll('minecraft:dye')
            -- Utils.dropUpAll('minecraft:redstone')
            Utils.dropUpAll(emerald)
        end
    end
end
--[[
    函数作用：进行有优先级的交易。用于交易的物品以及得到的物品都需要指定。
    参数：
    adv_arr 交易信息数组，数组前端优先级高。数组元素格式示例：{lose="minecraft:emerald",get="minecraft:apple",replenish_groups_num=2} replenish_num是补物品时补足的组数（可不填，默认为2）。
    replenishment_side 当机器人因为自身物品不够时，需要一个容器来补足物品，replenishment_side为这个容器的方向。不填或为nil时表示不补足物品，在物品不足时程序将结束。

 ]]
Utils.buyWithAdv = function(adv_arr, replenishment_side, block)
    for i, v in ipairs(adv_arr) do
        if v['replenish_groups_num'] == nil then
            v['replenish_groups_num'] = 2
        end
    end

    if block == nil then
        block = true
    end
    if #adv_arr == 0 then
        return false, 'all trades are disabled'                         --交易无货
    end
    local res, msg = Utils.Buyv2(adv_arr[1]['lose'], adv_arr[1]['get']) --尝试进行交易列表的第一个交易。
    if res == true then
        return true                                                     --交易成功，返回true
    elseif msg == 'not enough items to trade' then
        if replenishment_side ~= nil then
            -- 因机器人自身物品不够，无法完成交易。
            -- 这里分两种情况
            -- 1.指定了replenishment_side
            -- 尝试补货
            if block then
                --阻塞式补货，没有补到货则原地阻塞，反复尝试补货。
                for i = 1, adv_arr[1]['replenish_groups_num'] do
                    Utils.fillUp2SpecifiedNumofItemsWithSide(replenishment_side, adv_arr[1]['lose'], i * 64, nil, true)
                    os.sleep(1)
                end
            else
                --非阻塞式补货，没有补到货则返回
                --TODO
                if Utils.getInventorysTotalNumOfWithSide(replenishment_side, adv_arr[1]['lose']) < 64 then
                    return false, 'not enough items in the container'
                end
            end
        else
            -- 2.没有指定replenishment_side
            return false, 'not enough items to trade'
        end
    else
        --此交易无货，剪切数组，用递归的方法进行下一交易。
        return Utils.buyWithAdv(Utils.cut_arr_first(adv_arr), replenishment_side, block)
    end
end
Utils.geneIronMan = function(num_check)
    if num_check == nil then
        num_check = true
    end
    local pumpkin = 'minecraft:pumpkin'
    local iron_block = 'minecraft:iron_block'
    if num_check then
        local res, msg = Utils.numCheck({ [pumpkin] = 1, [iron_block] = 4 })
        if res == false then
            return res, msg
        end
    end

    Utils.placeAhead_S(iron_block)
    Utils.up()
    Utils.placeAhead_S(iron_block)
    Utils.moveLeft()
    Utils.placeAhead_S(iron_block)
    Utils.moveRight(2)
    Utils.placeAhead_S(iron_block)
    Utils.moveLeft()
    Utils.up()
    Utils.placeAhead_S(pumpkin)
    Utils.down(2)
    return true
end
Utils.geneMultiIronMan = function(num)
    local pumpkin = 'minecraft:pumpkin'
    local iron_block = 'minecraft:iron_block'
    local res, msg = Utils.numCheck({ [pumpkin] = 1 * num, [iron_block] = 4 * num })
    if res == false then
        return res, msg
    end

    for i = 1, num do
        Utils.geneIronMan(false)
    end
    return true
end
Utils.itemExist = function(itemName, itemLabel)
    local flag = false
    Utils.ForEachNotNilInternalInventory(function(id, stack)
        local name = stack.name
        local label = stack.label
        if itemLabel == nil then
            label = nil
        end
        if name == itemName and label == itemLabel then
            flag = true
            do
                return
            end
        end
    end)
    if flag == true then
        return true
    else
        return false
    end
end
Utils.getSeed = function()
    local ic = Utils.getInventoryController()
    bot.swingDown()
    -- local res, msg = bot.detectDown()
    local res, msg = bot.durability()
    if msg == 'tool cannot be damaged' then
        --还有作物架
        bot.useDown()
    else
        Utils.select(Utils.getSlotIdByItemName('ic2:crop_stick'), 1, ic.equip, true)
        bot.useDown()
    end
    res, msg = bot.durability()
    if msg == 'tool cannot be damaged' then
        --还有作物架
        bot.useDown()
    else
        Utils.select(Utils.getSlotIdByItemName('ic2:crop_stick'), 1, ic.equip, true)
        bot.useDown()
    end
end
Utils.regularlyGetSeed = function(num, sleepSec)
    if num == nil then
        num = 10000
    end
    if sleepSec == nil then
        sleepSec = 30 * 60
    end
    for i = 1, num do
        Utils.getSeed()
        Utils.back()
        Utils.moveLeft()
        Utils.getSeed()
        Utils.moveRight(2)
        Utils.getSeed()
        Utils.moveLeft()
        Utils.forward()
        Utils.dropUpAll('ic2:crop_seed_bag')
        os.sleep(sleepSec)
    end
end
--[[
    bot.equip存在线程安全问题
 ]]
Utils.equip = function()
    Utils.getLock(1, bot.equip)
end
Utils.getEquipmentStack = function()
    local ic = Utils.getInventoryController()
    local stack

    Utils.getLock(1, function()
        ic.equip()
        stack = ic.getStackInInternalSlot()
        ic.equip()
    end)

    return stack
end
Utils.copySeed = function()
    -- local ic = Utils.getInventoryController()
    local seedbag = 'ic2:crop_seed_bag'
    local stick = 'ic2:crop_stick'
    bot.swingDown()
    local res, msg = bot.detectDown()
    --1.空气 2.作物架
    if res == false then
        Utils.placeDown_S(stick)
    end
    Utils.placeDown_S(seedbag)
end
Utils.regularlyCopySeed = function(num, sleepSec, startWaitTime)
    if num == nil then
        num = 10000
    end
    if sleepSec == nil then
        sleepSec = 30 * 60
    end
    if startWaitTime == nil then
        startWaitTime = sleepSec
    end
    os.sleep(startWaitTime)
    for i = 1, num do
        -- os.sleep(sleepSec)
        -- Utils.dropUpAll('ic2:crop_seed_bag')
        Utils.copySeed()
        Utils.dropUpAll('ic2:crop_seed_bag')
        os.sleep(sleepSec)
    end
end
Utils.recPutSeed = function(length, width)
    local res, msg = Utils.numCheck({ ['ic2:crop_seed_bag'] = 1 })
    if res == false then
        return res, msg
    end
    Utils.recDo(length, width, Utils.placeDown_S, 'ic2:crop_seed_bag')
    return true
end
Utils.invervalPutSeed = function(length, width)
    local res, msg = Utils.numCheck({ ['ic2:crop_seed_bag'] = 1 })
    if res == false then
        return res, msg
    end
    Utils.recDoWithIJ(length, width, function(i, j)
        if (i + j) % 2 == 0 then
            Utils.placeDown_S('ic2:crop_seed_bag')
        end
    end)
    return true
end
Utils.recDo = function(length, width, func, ...)
    --local seedbag = 'ic2:crop_seed_bag'
    for i = 1, length do
        for j = 1, width do
            func(...)
            if j < width then
                Utils.forward()
            end
        end
        Utils.back(width - 1)
        if i < length then
            Utils.moveRight()
        end
    end
    Utils.moveLeft(length - 1)
end
Utils.recDoWithIJ = function(length, width, func, ...)
    --local seedbag = 'ic2:crop_seed_bag'
    for i = 1, length do
        for j = 1, width do
            func(i, j, ...)
            if j < width then
                Utils.forward()
            end
        end
        Utils.back(width - 1)
        if i < length then
            Utils.moveRight()
        end
    end
    Utils.moveLeft(length - 1)
end
Utils.harvest = function(length, width)
    Utils.recDo(length, width, bot.useDown)
end
Utils.regDo = function(num, sleepSec, afterfunc, func, ...)
    for i = 1, num do
        func(...)
        if afterfunc ~= nil then
            afterfunc()
        end
        os.sleep(sleepSec)
    end
end
Utils.regHarvestPotato = function(length, width)
    Utils.regDo(1000000, 15 * 60, function()
        Utils.dropUpAll('minecraft:poisonous_potato')
        Utils.dropUpAll('minecraft:potato')
    end, Utils.harvest, length, width)
end
Utils.stackEqual = function(stack, name, label)
    if label == nil then
        if stack.name == name then
            return true
        else
            return false
        end
    else
        if stack.name == name and stack.label == label then
            return true
        else
            return false
        end
    end
end
--[[
    放置多层地板
    height是指每层间距，也是相邻层内间距+1
 ]]
Utils.placeMultiFloor_S = function(itemName, length, width, height, layers)
    local res, msg = Utils.numCheck({ [itemName] = length * width * layers })
    if res == false then
        return res, msg
    end
    for i = 1, layers do
        Utils.placeFloor_S(itemName, length, width, true, false)
        if i < layers then
            Utils.up(height)
        end
    end
end
--[[
    根据物品名获取数量
]]
Utils.tunnelSend_getItemCountByName = function(itemName)
    local res = Utils.tunnelSend({ name = itemName })
    if res['res'] then
        return res['data']
    else
        return 0
    end
end
--[[
    p2p包发送接口
]]
Utils.tunnelSend = function(table)
    local tunnel = Component.tunnel
    tunnel.send(Ser.serialize(table))
    local a, b, c, d, e, f = event.pull('modem_message')
    return Ser.unserialize(f)
end

--[[
    在自动采矿机应该在的位置放置方块。
    四个参数的意思分别是：
    放置的方块的名称
    横向放置方块的数量（网状放置）
    纵向放置方块的数量
    是否强制移动（是：机器人在移动时尝试破坏阻挡它的方块。否：机器人在被方块阻挡后原地等待，直至前方方块消失为止。）
    Place blocks in the position where the automatic mining machine should be placed.
    The meanings of the four parameters are:
    The name of the placed block
    Number of horizontally placed blocks (mesh placement)
    Number of vertically placed blocks
    Whether to force movement (Yes: The robot attempts to break the block blocking it while moving. No: The robot waits in place after being blocked by the block until the block in front disappears.)
 ]]
Utils.placeAutoMinerPoints = function(blockName, x_num, y_num, forcemoving)
    -- test
    local res, msg = Utils.numCheck({ [blockName] = x_num * y_num })
    if res == false then
        return res, msg
    end
    if forcemoving == nil then
        --默认会强制移动
        forcemoving = true
    end

    for i = 1, x_num do
        for j = 1, y_num do
            Utils.placeDown_S(blockName, false)
            if j < y_num then
                Utils.forward(65, forcemoving)
            else
                Utils.back(65 * (y_num - 1))
            end
        end

        if i == x_num then
            Utils.turnLeft()
            Utils.forward(65 * (x_num - 1), forcemoving)
            Utils.turnRight()
        else
            Utils.turnRight()
            Utils.forward(65, forcemoving)
            Utils.turnLeft()
        end
    end

    return true
end
--[[ 
    放置多层9x9泥土，机器人往上走一格然后放置
 ]]
Utils.placeMultiDirtFloor = function(layersNum)
    local res, msg = Utils.numCheck({ ['minecraft:dirt'] = layersNum * 9 * 9 })
    if res == false then
        return res, msg
    end
    Utils.up()
    for i = 1, layersNum do
        Utils.placeFloor_S('minecraft:dirt', 9, 9, true)
        Utils.up(5)
    end

end
Utils.buildMultiLayerHCWithoutFloor_S = function(blockName, length, width, height, layers, numCheck)
    if (numCheck == nil) then
        numCheck = true
    end
    if (numCheck == true) then
        local res, msg = Utils.numCheck({ [blockName] = layers * (width * length + (height - 1) * (2 * (length + width) - 4)) })
        if res == false then
            return res, msg
        end
    end
    for i = 1, layers do
        Utils.buildHollowCuboidWithoutFloor_S(blockName, length, width, height, False)
    end
end

Utils.intervalPutSeedAndCropStick = function(length, width)

    local res, msg = Utils.numCheck({ ['ic2:crop_seed_bag'] = 1, ['ic2:crop_stick'] = (length * width) // 2 })
    local ic = require('component').inventory_controller
    if res == false then
        return res, msg
    end
    Utils.recDoWithIJ(length, width, function(i, j)
        if (i + j) % 2 == 0 then
            Utils.placeDown_S('ic2:crop_seed_bag')
        else
            local res, msg = bot.durability()
            if msg == 'tool cannot be damaged' then
                --还有作物架
                bot.useDown()
            else
                Utils.select(Utils.getSlotIdByItemName('ic2:crop_stick'), 1, ic.equip, true)
                bot.useDown()
            end

        end
    end)
    return true
end
Utils.placeDownBySlotId = function(slotId, side)
    Utils.select(
            slotId,
            1,
            function()
                while (bot.placeDown(side) == false) do
                    local a, b = bot.detectDown()
                    if (b == "solid") then
                        break
                    end
                    os.sleep(3)
                end
            end
    )
    -- selectLocked = 0
    return true
end
--[[
杂交，同intervalPutSeedAndCropStick
如果length>=width,相邻列作物不同
如果length<width,相邻行作物不同
]]
Utils.hybridize = function(length, width)
    local idFirst = Utils.getFirstSlotIdWithConditions(function(stack)
        return stack.name == 'ic2:crop_seed_bag'
    end)
    if idFirst == -1 then
        return false, 'Not enough crop seed bags'
    end
    local idSecond = Utils.getFirstSlotIdWithIdConditions(function(id, stack)
        return id ~= idFirst and stack.name == 'ic2:crop_seed_bag'
    end)
    if idSecond == -1 then
        return false, 'Not enough crop seed bags'
    end
    local res, msg = Utils.numCheck({ ['ic2:crop_stick'] = (length * width) // 2 })
    if res == false then
        return res, msg
    end
    local ic = require('component').inventory_controller

    Utils.recDoWithIJ(length, width, function(i, j)
        if (i + j) % 2 == 0 then
            if length >= width then
                --列数多，按列杂交
                if i % 2 == 1 then
                    Utils.placeDownBySlotId(idFirst)
                else
                    Utils.placeDownBySlotId(idSecond)
                end
            else
                --行数多，按行杂交
                if j % 2 == 1 then
                    Utils.placeDownBySlotId(idFirst)
                else
                    Utils.placeDownBySlotId(idSecond)
                end
            end
            --Utils.placeDown_S('ic2:crop_seed_bag')
        else
            local res, msg = bot.durability()
            if msg == 'tool cannot be damaged' then
                --还有作物架
                bot.useDown()
            else
                Utils.select(Utils.getSlotIdByItemName('ic2:crop_stick'), 1, ic.equip, true)
                bot.useDown()
            end

        end
    end)
    return true
end
Utils.recPutSeed2x4x9 = function()
    Utils.recPutSeed(4, 9)
    Utils.moveRight(5)
    Utils.recPutSeed(4, 9)
    Utils.moveLeft(5)
end
--[[
多层耕地，每层4x9x2,高度自定义
--]]
Utils.multiLayerCultivate = function(height, layers)
    for i = 1, layers do
        Utils.recDo(4, 9, bot.useDown)
        Utils.moveRight(5)
        Utils.recDo(4, 9, bot.useDown)
        Utils.moveLeft(5)
        if i < layers then
            Utils.back()
            Utils.up(height)
            Utils.forward()
        end
    end
end
--[[
多层耕地放上作物架，每层4x9x2,高度自定义
--]]
Utils.multiLayerCropStick = function(height, layers, numCheck)
    if numCheck == nil then
        numCheck = true
    end
    if numCheck == true then
        local res, msg = Utils.numCheck({ ['ic2:crop_stick'] = layers * 72 })
        if res == false then
            return res, msg
        end
    end
    for i = 1, layers do
        Utils.placeFloor_S('ic2:crop_stick', 4, 9, true)
        Utils.moveRight(5)
        Utils.placeFloor_S('ic2:crop_stick', 4, 9, true)
        Utils.moveLeft(5)
        if i < layers then
            Utils.back()
            Utils.up(height)
            Utils.forward()
        end
    end
end
--[[
多层耕地放上X，每层4x9x2,高度自定义
--]]
Utils.multiLayerCropPlace = function(itemName, height, layers, numCheck)
    if numCheck == nil then
        numCheck = true
    end
    if numCheck == true then
        local res, msg = Utils.numCheck({ [itemName] = layers * 72 })
        if res == false then
            return res, msg
        end
    end
    for i = 1, layers do
        Utils.placeFloor_S(itemName, 4, 9, true, false)
        Utils.moveRight(5)
        Utils.placeFloor_S(itemName, 4, 9, true, false)
        Utils.moveLeft(5)
        if i < layers then
            Utils.back()
            Utils.up(height)
            Utils.forward()
        end
    end
end

--[[
    由于靶丸发电需要的物品数量过多，一次性难以将多层的靶丸发电厂完全做好，下面的这个函数在每层发电厂搭建之前，都会检查三种物品是否足够建好这一层。
    如果材料不够，后退一格后来到第一层（即机器人最开始所在高度的背后一格），在这一格的背后备有靶丸，左边备有发电机，右边备有玻璃纤维导线。机器人先查看背包的空余空间。之后按比例12:2:1填充空余空间。
    填充后，回到之前所在层进行工作。
 ]]
Utils.placeMultiFloor32EUAutoFillBackPackV2 = function(length, width, layers)
    local ic = Utils.getInventoryController()
    if ic == nil then
        return false, 'no inventory_controller'
    end
    local te = "Radioisotope Thermoelectric Generator"
    local nu = "Pellets of RTG Fuel"
    local ca = "Glass Fibre Cable"

    for i = 1, layers do
        local horizontalSlots = math.ceil(width / 2)  -- 实际每行放置的发电机/导线数量
        local required_te = 2 * length * horizontalSlots  -- 上下两层发电机
        local required_nu = 12 * length * horizontalSlots  -- 每个发电机填充6燃料 x2层
        local required_ca = 1 * length * horizontalSlots   -- 中间导线层
        local res, msg = Utils.numNameLabelCheck(
                {
                    [{ "ic2:te", te }] = required_te,
                    [{ "ic2:nuclear", nu }] = required_nu,
                    [{ "ic2:cable", ca }] = required_ca
                }
        )
        if res == false then
            --机器人背包的材料已经不足以搭建这一层了
            local res2, msg2
            Utils.back()
            Utils.down(3 * (i - 1))
            local emptySlotNumber = Utils.getEmptyInternalSlotNumber() --空格子数*64
            local numof15M64 = math.floor(emptySlotNumber / 15)        --空格子数地板除以15
            Utils.turnLeft()
            while true do
                res2, msg2 = Utils.suckSpecifiedNumofItemsWithSide(sides.forward, 'ic2:te', numof15M64 * 64 * 2, te)
                if res2 == true then
                    break
                end
                os.sleep(10)
                print(msg2)
            end

            Utils.turnLeft()
            while true do
                res2, msg2 = Utils.suckSpecifiedNumofItemsWithSide(sides.forward, 'ic2:nuclear', numof15M64 * 64 * 12, nu)
                if res2 == true then
                    break
                end
                os.sleep(10)
                print(msg2)
            end

            Utils.turnLeft()
            while true do
                res2, msg2 = Utils.suckSpecifiedNumofItemsWithSide(sides.forward, 'ic2:cable', numof15M64 * 64 * 1, ca)
                if res2 == true then
                    break
                end
                os.sleep(10)
                print(msg2)
            end

            Utils.turnLeft()
            Utils.up(3 * (i - 1))
            Utils.forward()
        end

        Utils.placeOneFloor32EU_V2(length, width, false)
    end
    return true
end

Utils.placeOneFloor32EU_V2 = function(length, width, numCheck)
    local ic = Utils.getInventoryController()
    if ic == nil then
        return false, 'no inventory_controller'
    end
    if numCheck == nil then
        numCheck = true
    end
    local te = "Radioisotope Thermoelectric Generator"
    local nu = "Pellets of RTG Fuel"
    local ca = "Glass Fibre Cable"
    if numCheck then
        -- 材料需求调整为原来的 1/2（水平间隔放置）
        local horizontalSlots = math.ceil(width / 2)  -- 实际每行放置的发电机/导线数量
        local required_te = 2 * length * horizontalSlots  -- 上下两层发电机
        local required_nu = 12 * length * horizontalSlots  -- 每个发电机填充6燃料 x2层
        local required_ca = 1 * length * horizontalSlots   -- 中间导线层
        local res, msg = Utils.numNameLabelCheck(
                {
                    [{ "ic2:te", te }] = required_te,
                    [{ "ic2:nuclear", nu }] = required_nu,
                    [{ "ic2:cable", ca }] = required_ca
                }
        )
        if res == false then
            return res, msg
        end
    end

    -- 第一层：底层发电机（间隔放置）
    Utils.up()
    for i = 1, length do
        for j = 1, width do
            if j % 2 == 1 then  -- 仅奇数位置放置
                Utils.placeDown_S("ic2:te", false, te)
                for k = 2, 7 do  -- 填充燃料
                    Utils.select(Utils.getSlotIdByItemName("ic2:nuclear", nu), 1, function()
                        ic.dropIntoSlot(sides.bottom, k, 1)
                    end, true)
                end
            end
            if j < width then
                Utils.forward()  -- 移动逻辑不变，但实际放置间隔
            end
        end
        Utils.back(width - 1)
        if i < length then
            Utils.moveRight()
        end
    end
    Utils.moveLeft(length - 1)

    -- 第二层：中间导线（间隔放置，与底层对齐）
    Utils.up()
    for i = 1, length do
        for j = 1, width do
            if j % 2 == 1 then  -- 仅奇数位置放置
                Utils.placeDown_S("ic2:cable", false, ca)
            end
            if j < width then
                Utils.forward()
            end
        end
        Utils.back(width - 1)
        if i < length then
            Utils.moveRight()
        end
    end
    Utils.moveLeft(length - 1)

    -- 第三层：顶层发电机（间隔放置，与底层对齐）
    Utils.up()
    for i = 1, length do
        for j = 1, width do
            if j % 2 == 1 then
                Utils.placeDown_S("ic2:te", false, te)
                for k = 2, 7 do
                    Utils.select(Utils.getSlotIdByItemName("ic2:nuclear", nu), 1, function()
                        ic.dropIntoSlot(sides.bottom, k, 1)
                    end, true)
                end
            end
            if j < width then
                Utils.forward()
            end
        end
        Utils.back(width - 1)
        if i < length then
            Utils.moveRight()
        end
    end
    Utils.moveLeft(length - 1)
    return true
end

return Utils

